Mercurial > hg > hg-fastimport
comparison hgext3rd/fastimport/vendor/python_fastimport/tests/test_parser.py @ 86:28704a2a7461 vendor/python-fastimport
Import python-fastimport-0.9.8
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Tue, 19 Jan 2021 22:56:34 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 85:1f5544a8870b | 86:28704a2a7461 |
|---|---|
| 1 # Copyright (C) 2008 Canonical Ltd | |
| 2 # | |
| 3 # This program is free software; you can redistribute it and/or modify | |
| 4 # it under the terms of the GNU General Public License as published by | |
| 5 # the Free Software Foundation; either version 2 of the License, or | |
| 6 # (at your option) any later version. | |
| 7 # | |
| 8 # This program is distributed in the hope that it will be useful, | |
| 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 11 # GNU General Public License for more details. | |
| 12 # | |
| 13 # You should have received a copy of the GNU General Public License | |
| 14 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 15 | |
| 16 """Test the Import parsing""" | |
| 17 import io | |
| 18 import time | |
| 19 import unittest | |
| 20 | |
| 21 from fastimport import ( | |
| 22 commands, | |
| 23 errors, | |
| 24 parser, | |
| 25 ) | |
| 26 | |
| 27 | |
| 28 class TestLineBasedParser(unittest.TestCase): | |
| 29 | |
| 30 def test_push_line(self): | |
| 31 s = io.BytesIO(b"foo\nbar\nbaz\n") | |
| 32 p = parser.LineBasedParser(s) | |
| 33 self.assertEqual(b'foo', p.next_line()) | |
| 34 self.assertEqual(b'bar', p.next_line()) | |
| 35 p.push_line(b'bar') | |
| 36 self.assertEqual(b'bar', p.next_line()) | |
| 37 self.assertEqual(b'baz', p.next_line()) | |
| 38 self.assertEqual(None, p.next_line()) | |
| 39 | |
| 40 def test_read_bytes(self): | |
| 41 s = io.BytesIO(b"foo\nbar\nbaz\n") | |
| 42 p = parser.LineBasedParser(s) | |
| 43 self.assertEqual(b'fo', p.read_bytes(2)) | |
| 44 self.assertEqual(b'o\nb', p.read_bytes(3)) | |
| 45 self.assertEqual(b'ar', p.next_line()) | |
| 46 # Test that the line buffer is ignored | |
| 47 p.push_line(b'bar') | |
| 48 self.assertEqual(b'baz', p.read_bytes(3)) | |
| 49 # Test missing bytes | |
| 50 self.assertRaises(errors.MissingBytes, p.read_bytes, 10) | |
| 51 | |
| 52 def test_read_until(self): | |
| 53 # TODO | |
| 54 return | |
| 55 s = io.BytesIO(b"foo\nbar\nbaz\nabc\ndef\nghi\n") | |
| 56 p = parser.LineBasedParser(s) | |
| 57 self.assertEqual(b'foo\nbar', p.read_until(b'baz')) | |
| 58 self.assertEqual(b'abc', p.next_line()) | |
| 59 # Test that the line buffer is ignored | |
| 60 p.push_line(b'abc') | |
| 61 self.assertEqual(b'def', p.read_until(b'ghi')) | |
| 62 # Test missing terminator | |
| 63 self.assertRaises(errors.MissingTerminator, p.read_until(b'>>>')) | |
| 64 | |
| 65 | |
| 66 # Sample text | |
| 67 _sample_import_text = b""" | |
| 68 progress completed | |
| 69 # Test blob formats | |
| 70 blob | |
| 71 mark :1 | |
| 72 data 4 | |
| 73 aaaablob | |
| 74 data 5 | |
| 75 bbbbb | |
| 76 # Commit formats | |
| 77 commit refs/heads/master | |
| 78 mark :2 | |
| 79 committer bugs bunny <bugs@bunny.org> now | |
| 80 data 14 | |
| 81 initial import | |
| 82 M 644 inline README | |
| 83 data 18 | |
| 84 Welcome from bugs | |
| 85 commit refs/heads/master | |
| 86 committer <bugs@bunny.org> now | |
| 87 data 13 | |
| 88 second commit | |
| 89 from :2 | |
| 90 M 644 inline README | |
| 91 data 23 | |
| 92 Welcome from bugs, etc. | |
| 93 # Miscellaneous | |
| 94 checkpoint | |
| 95 progress completed | |
| 96 # Test a commit without sub-commands (bug #351717) | |
| 97 commit refs/heads/master | |
| 98 mark :3 | |
| 99 author <bugs@bunny.org> now | |
| 100 committer <bugs@bunny.org> now | |
| 101 data 20 | |
| 102 first commit, empty | |
| 103 # Test a commit with a heredoc-style (delimited_data) messsage (bug #400960) | |
| 104 commit refs/heads/master | |
| 105 mark :4 | |
| 106 author <bugs@bunny.org> now | |
| 107 committer <bugs@bunny.org> now | |
| 108 data <<EOF | |
| 109 Commit with heredoc-style message | |
| 110 EOF | |
| 111 # Test a "submodule"/tree-reference | |
| 112 commit refs/heads/master | |
| 113 mark :5 | |
| 114 author <bugs@bunny.org> now | |
| 115 committer <bugs@bunny.org> now | |
| 116 data 15 | |
| 117 submodule test | |
| 118 M 160000 rev-id tree-id | |
| 119 # Test features | |
| 120 feature whatever | |
| 121 feature foo=bar | |
| 122 # Test commit with properties | |
| 123 commit refs/heads/master | |
| 124 mark :6 | |
| 125 committer <bugs@bunny.org> now | |
| 126 data 18 | |
| 127 test of properties | |
| 128 property p1 | |
| 129 property p2 5 hohum | |
| 130 property p3 16 alpha | |
| 131 beta | |
| 132 gamma | |
| 133 property p4 8 whatever | |
| 134 # Test a commit with multiple authors | |
| 135 commit refs/heads/master | |
| 136 mark :7 | |
| 137 author Fluffy <fluffy@bunny.org> now | |
| 138 author Daffy <daffy@duck.org> now | |
| 139 author Donald <donald@duck.org> now | |
| 140 committer <bugs@bunny.org> now | |
| 141 data 17 | |
| 142 multi-author test | |
| 143 """ | |
| 144 | |
| 145 _timefunc = time.time | |
| 146 class TestImportParser(unittest.TestCase): | |
| 147 def setUp(self): | |
| 148 self.fake_time = 42.0123 | |
| 149 time.time = lambda: self.fake_time | |
| 150 def tearDown(self): | |
| 151 time.time = _timefunc | |
| 152 del self.fake_time | |
| 153 | |
| 154 def test_iter_commands(self): | |
| 155 s = io.BytesIO(_sample_import_text) | |
| 156 p = parser.ImportParser(s) | |
| 157 result = [] | |
| 158 for cmd in p.iter_commands(): | |
| 159 result.append(cmd) | |
| 160 if cmd.name == b'commit': | |
| 161 for fc in cmd.iter_files(): | |
| 162 result.append(fc) | |
| 163 | |
| 164 self.assertEqual(len(result), 17) | |
| 165 cmd1 = result.pop(0) | |
| 166 self.assertEqual(b'progress', cmd1.name) | |
| 167 self.assertEqual(b'completed', cmd1.message) | |
| 168 cmd2 = result.pop(0) | |
| 169 self.assertEqual(b'blob', cmd2.name) | |
| 170 self.assertEqual(b'1', cmd2.mark) | |
| 171 self.assertEqual(b':1', cmd2.id) | |
| 172 self.assertEqual(b'aaaa', cmd2.data) | |
| 173 self.assertEqual(4, cmd2.lineno) | |
| 174 cmd3 = result.pop(0) | |
| 175 self.assertEqual(b'blob', cmd3.name) | |
| 176 self.assertEqual(b'@7', cmd3.id) | |
| 177 self.assertEqual(None, cmd3.mark) | |
| 178 self.assertEqual(b'bbbbb', cmd3.data) | |
| 179 self.assertEqual(7, cmd3.lineno) | |
| 180 cmd4 = result.pop(0) | |
| 181 self.assertEqual(b'commit', cmd4.name) | |
| 182 self.assertEqual(b'2', cmd4.mark) | |
| 183 self.assertEqual(b':2', cmd4.id) | |
| 184 self.assertEqual(b'initial import', cmd4.message) | |
| 185 | |
| 186 self.assertEqual((b'bugs bunny', b'bugs@bunny.org', self.fake_time, 0), cmd4.committer) | |
| 187 # namedtuple attributes | |
| 188 self.assertEqual(b'bugs bunny', cmd4.committer.name) | |
| 189 self.assertEqual(b'bugs@bunny.org', cmd4.committer.email) | |
| 190 self.assertEqual(self.fake_time, cmd4.committer.timestamp) | |
| 191 self.assertEqual(0, cmd4.committer.timezone) | |
| 192 | |
| 193 self.assertEqual(None, cmd4.author) | |
| 194 self.assertEqual(11, cmd4.lineno) | |
| 195 self.assertEqual(b'refs/heads/master', cmd4.ref) | |
| 196 self.assertEqual(None, cmd4.from_) | |
| 197 self.assertEqual([], cmd4.merges) | |
| 198 file_cmd1 = result.pop(0) | |
| 199 self.assertEqual(b'filemodify', file_cmd1.name) | |
| 200 self.assertEqual(b'README', file_cmd1.path) | |
| 201 self.assertEqual(0o100644, file_cmd1.mode) | |
| 202 self.assertEqual(b'Welcome from bugs\n', file_cmd1.data) | |
| 203 cmd5 = result.pop(0) | |
| 204 self.assertEqual(b'commit', cmd5.name) | |
| 205 self.assertEqual(None, cmd5.mark) | |
| 206 self.assertEqual(b'@19', cmd5.id) | |
| 207 self.assertEqual(b'second commit', cmd5.message) | |
| 208 self.assertEqual((b'', b'bugs@bunny.org', self.fake_time, 0), cmd5.committer) | |
| 209 self.assertEqual(None, cmd5.author) | |
| 210 self.assertEqual(19, cmd5.lineno) | |
| 211 self.assertEqual(b'refs/heads/master', cmd5.ref) | |
| 212 self.assertEqual(b':2', cmd5.from_) | |
| 213 self.assertEqual([], cmd5.merges) | |
| 214 file_cmd2 = result.pop(0) | |
| 215 self.assertEqual(b'filemodify', file_cmd2.name) | |
| 216 self.assertEqual(b'README', file_cmd2.path) | |
| 217 self.assertEqual(0o100644, file_cmd2.mode) | |
| 218 self.assertEqual(b'Welcome from bugs, etc.', file_cmd2.data) | |
| 219 cmd6 = result.pop(0) | |
| 220 self.assertEqual(cmd6.name, b'checkpoint') | |
| 221 cmd7 = result.pop(0) | |
| 222 self.assertEqual(b'progress', cmd7.name) | |
| 223 self.assertEqual(b'completed', cmd7.message) | |
| 224 cmd = result.pop(0) | |
| 225 self.assertEqual(b'commit', cmd.name) | |
| 226 self.assertEqual(b'3', cmd.mark) | |
| 227 self.assertEqual(None, cmd.from_) | |
| 228 cmd = result.pop(0) | |
| 229 self.assertEqual(b'commit', cmd.name) | |
| 230 self.assertEqual(b'4', cmd.mark) | |
| 231 self.assertEqual(b'Commit with heredoc-style message\n', cmd.message) | |
| 232 cmd = result.pop(0) | |
| 233 self.assertEqual(b'commit', cmd.name) | |
| 234 self.assertEqual(b'5', cmd.mark) | |
| 235 self.assertEqual(b'submodule test\n', cmd.message) | |
| 236 file_cmd1 = result.pop(0) | |
| 237 self.assertEqual(b'filemodify', file_cmd1.name) | |
| 238 self.assertEqual(b'tree-id', file_cmd1.path) | |
| 239 self.assertEqual(0o160000, file_cmd1.mode) | |
| 240 self.assertEqual(b"rev-id", file_cmd1.dataref) | |
| 241 cmd = result.pop(0) | |
| 242 self.assertEqual(b'feature', cmd.name) | |
| 243 self.assertEqual(b'whatever', cmd.feature_name) | |
| 244 self.assertEqual(None, cmd.value) | |
| 245 cmd = result.pop(0) | |
| 246 self.assertEqual(b'feature', cmd.name) | |
| 247 self.assertEqual(b'foo', cmd.feature_name) | |
| 248 self.assertEqual(b'bar', cmd.value) | |
| 249 cmd = result.pop(0) | |
| 250 self.assertEqual(b'commit', cmd.name) | |
| 251 self.assertEqual(b'6', cmd.mark) | |
| 252 self.assertEqual(b'test of properties', cmd.message) | |
| 253 self.assertEqual({ | |
| 254 b'p1': None, | |
| 255 b'p2': b'hohum', | |
| 256 b'p3': b'alpha\nbeta\ngamma', | |
| 257 b'p4': b'whatever', | |
| 258 }, cmd.properties) | |
| 259 cmd = result.pop(0) | |
| 260 self.assertEqual(b'commit', cmd.name) | |
| 261 self.assertEqual(b'7', cmd.mark) | |
| 262 self.assertEqual(b'multi-author test', cmd.message) | |
| 263 self.assertEqual(b'', cmd.committer[0]) | |
| 264 self.assertEqual(b'bugs@bunny.org', cmd.committer[1]) | |
| 265 self.assertEqual(b'Fluffy', cmd.author[0]) | |
| 266 self.assertEqual(b'fluffy@bunny.org', cmd.author[1]) | |
| 267 self.assertEqual(b'Daffy', cmd.more_authors[0][0]) | |
| 268 self.assertEqual(b'daffy@duck.org', cmd.more_authors[0][1]) | |
| 269 self.assertEqual(b'Donald', cmd.more_authors[1][0]) | |
| 270 self.assertEqual(b'donald@duck.org', cmd.more_authors[1][1]) | |
| 271 | |
| 272 def test_done_feature_missing_done(self): | |
| 273 s = io.BytesIO(b"""feature done | |
| 274 """) | |
| 275 p = parser.ImportParser(s) | |
| 276 cmds = p.iter_commands() | |
| 277 self.assertEqual(b"feature", next(cmds).name) | |
| 278 self.assertRaises(errors.PrematureEndOfStream, lambda: next(cmds)) | |
| 279 | |
| 280 def test_done_with_feature(self): | |
| 281 s = io.BytesIO(b"""feature done | |
| 282 done | |
| 283 more data | |
| 284 """) | |
| 285 p = parser.ImportParser(s) | |
| 286 cmds = p.iter_commands() | |
| 287 self.assertEqual(b"feature", next(cmds).name) | |
| 288 self.assertRaises(StopIteration, lambda: next(cmds)) | |
| 289 | |
| 290 def test_done_without_feature(self): | |
| 291 s = io.BytesIO(b"""done | |
| 292 more data | |
| 293 """) | |
| 294 p = parser.ImportParser(s) | |
| 295 cmds = p.iter_commands() | |
| 296 self.assertEqual([], list(cmds)) | |
| 297 | |
| 298 | |
| 299 class TestStringParsing(unittest.TestCase): | |
| 300 | |
| 301 def test_unquote(self): | |
| 302 s = br'hello \"sweet\" wo\\r\tld' | |
| 303 self.assertEqual(br'hello "sweet" wo\r' + b'\tld', | |
| 304 parser._unquote_c_string(s)) | |
| 305 | |
| 306 | |
| 307 class TestPathPairParsing(unittest.TestCase): | |
| 308 | |
| 309 def test_path_pair_simple(self): | |
| 310 p = parser.ImportParser(b'') | |
| 311 self.assertEqual([b'foo', b'bar'], p._path_pair(b'foo bar')) | |
| 312 | |
| 313 def test_path_pair_spaces_in_first(self): | |
| 314 p = parser.ImportParser("") | |
| 315 self.assertEqual([b'foo bar', b'baz'], | |
| 316 p._path_pair(b'"foo bar" baz')) | |
| 317 | |
| 318 | |
| 319 class TestTagParsing(unittest.TestCase): | |
| 320 | |
| 321 def test_tagger_with_email(self): | |
| 322 p = parser.ImportParser(io.BytesIO( | |
| 323 b"tag refs/tags/v1.0\n" | |
| 324 b"from :xxx\n" | |
| 325 b"tagger Joe Wong <joe@example.com> 1234567890 -0600\n" | |
| 326 b"data 11\n" | |
| 327 b"create v1.0")) | |
| 328 cmds = list(p.iter_commands()) | |
| 329 self.assertEqual(1, len(cmds)) | |
| 330 self.assertTrue(isinstance(cmds[0], commands.TagCommand)) | |
| 331 self.assertEqual(cmds[0].tagger, | |
| 332 (b'Joe Wong', b'joe@example.com', 1234567890.0, -21600)) | |
| 333 | |
| 334 def test_tagger_no_email_strict(self): | |
| 335 p = parser.ImportParser(io.BytesIO( | |
| 336 b"tag refs/tags/v1.0\n" | |
| 337 b"from :xxx\n" | |
| 338 b"tagger Joe Wong\n" | |
| 339 b"data 11\n" | |
| 340 b"create v1.0")) | |
| 341 self.assertRaises(errors.BadFormat, list, p.iter_commands()) | |
| 342 | |
| 343 def test_tagger_no_email_not_strict(self): | |
| 344 p = parser.ImportParser(io.BytesIO( | |
| 345 b"tag refs/tags/v1.0\n" | |
| 346 b"from :xxx\n" | |
| 347 b"tagger Joe Wong\n" | |
| 348 b"data 11\n" | |
| 349 b"create v1.0"), strict=False) | |
| 350 cmds = list(p.iter_commands()) | |
| 351 self.assertEqual(1, len(cmds)) | |
| 352 self.assertTrue(isinstance(cmds[0], commands.TagCommand)) | |
| 353 self.assertEqual(cmds[0].tagger[:2], (b'Joe Wong', None)) |
