38421cdbce897422b47fe49968cb6de9eb894357
[jelmer/python-fastimport.git] / tests / test_generic_processor.py
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, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17 import time
18
19 from bzrlib import (
20     branch,
21     tests,
22     )
23
24 from bzrlib.plugins.fastimport import (
25     commands,
26     errors,
27     )
28
29 from bzrlib.plugins.fastimport.processors import (
30     generic_processor,
31     )
32
33
34 class TestCaseForGenericProcessor(tests.TestCaseWithTransport):
35
36     branch_format = "pack-0.92"
37
38     def get_handler(self):
39         branch = self.make_branch('.', format=self.branch_format)
40         handler = generic_processor.GenericProcessor(branch.bzrdir)
41         return handler, branch
42
43     # FIXME: [] as a default is bad, as it is mutable, but I want
44     # to use None to mean "don't check this".
45     def assertChanges(self, branch, revno, expected_added=[],
46             expected_removed=[], expected_modified=[],
47             expected_renamed=[], expected_kind_changed=[]):
48         """Check the changes introduced in a revision of a branch.
49
50         This method checks that a revision introduces expected changes.
51         The required changes are passed in as a list, where
52         each entry contains the needed information about the change.
53
54         If you do not wish to assert anything about a particular
55         category then pass None instead.
56
57         branch: The branch.
58         revno: revision number of revision to check.
59         expected_added: a list of (filename,) tuples that must have
60             been added in the delta.
61         expected_removed: a list of (filename,) tuples that must have
62             been removed in the delta.
63         expected_modified: a list of (filename,) tuples that must have
64             been modified in the delta.
65         expected_renamed: a list of (old_path, new_path) tuples that
66             must have been renamed in the delta.
67         expected_kind_changed: a list of (path, old_kind, new_kind) tuples
68             that must have been changed in the delta.
69         :return: revtree1, revtree2
70         """
71         repo = branch.repository
72         revtree1 = repo.revision_tree(branch.get_rev_id(revno - 1))
73         revtree2 = repo.revision_tree(branch.get_rev_id(revno))
74         changes = revtree2.changes_from(revtree1)
75         self._check_changes(changes, expected_added, expected_removed,
76             expected_modified, expected_renamed, expected_kind_changed)
77         return revtree1, revtree2
78
79     def _check_changes(self, changes, expected_added=[],
80             expected_removed=[], expected_modified=[],
81             expected_renamed=[], expected_kind_changed=[]):
82         """Check the changes in a TreeDelta
83
84         This method checks that the TreeDelta contains the expected
85         modifications between the two trees that were used to generate
86         it. The required changes are passed in as a list, where
87         each entry contains the needed information about the change.
88
89         If you do not wish to assert anything about a particular
90         category then pass None instead.
91
92         changes: The TreeDelta to check.
93         expected_added: a list of (filename,) tuples that must have
94             been added in the delta.
95         expected_removed: a list of (filename,) tuples that must have
96             been removed in the delta.
97         expected_modified: a list of (filename,) tuples that must have
98             been modified in the delta.
99         expected_renamed: a list of (old_path, new_path) tuples that
100             must have been renamed in the delta.
101         expected_kind_changed: a list of (path, old_kind, new_kind) tuples
102             that must have been changed in the delta.
103         """
104         renamed = changes.renamed
105         added = changes.added
106         removed = changes.removed
107         modified = changes.modified
108         kind_changed = changes.kind_changed
109         if expected_renamed is not None:
110             self.assertEquals(len(renamed), len(expected_renamed),
111                 "%s is renamed, expected %s" % (renamed, expected_renamed))
112             renamed_files = [(item[0], item[1]) for item in renamed]
113             for expected_renamed_entry in expected_renamed:
114                 self.assertTrue(expected_renamed_entry in renamed_files,
115                     "%s is not renamed, %s are" % (str(expected_renamed_entry),
116                         renamed_files))
117         if expected_added is not None:
118             self.assertEquals(len(added), len(expected_added),
119                 "%s is added" % str(added))
120             added_files = [(item[0],) for item in added]
121             for expected_added_entry in expected_added:
122                 self.assertTrue(expected_added_entry in added_files,
123                     "%s is not added, %s are" % (str(expected_added_entry),
124                         added_files))
125         if expected_removed is not None:
126             self.assertEquals(len(removed), len(expected_removed),
127                 "%s is removed" % str(removed))
128             removed_files = [(item[0],) for item in removed]
129             for expected_removed_entry in expected_removed:
130                 self.assertTrue(expected_removed_entry in removed_files,
131                     "%s is not removed, %s are" % (str(expected_removed_entry),
132                         removed_files))
133         if expected_modified is not None:
134             self.assertEquals(len(modified), len(expected_modified),
135                 "%s is modified" % str(modified))
136             modified_files = [(item[0],) for item in modified]
137             for expected_modified_entry in expected_modified:
138                 self.assertTrue(expected_modified_entry in modified_files,
139                     "%s is not modified, %s are" % (
140                     str(expected_modified_entry), modified_files))
141         if expected_kind_changed is not None:
142             self.assertEquals(len(kind_changed), len(expected_kind_changed),
143                 "%s is kind-changed, expected %s" % (kind_changed,
144                     expected_kind_changed))
145             kind_changed_files = [(item[0], item[2], item[3])
146                 for item in kind_changed]
147             for expected_kind_changed_entry in expected_kind_changed:
148                 self.assertTrue(expected_kind_changed_entry in
149                     kind_changed_files, "%s is not kind-changed, %s are" % (
150                     str(expected_kind_changed_entry), kind_changed_files))
151
152     def assertContent(self, branch, tree, path, content):
153         file_id = tree.inventory.path2id(path)
154         branch.lock_read()
155         self.addCleanup(branch.unlock)
156         self.assertEqual(tree.get_file_text(file_id), content)
157
158     def assertSymlinkTarget(self, branch, tree, path, target):
159         file_id = tree.inventory.path2id(path)
160         branch.lock_read()
161         self.addCleanup(branch.unlock)
162         self.assertEqual(tree.get_symlink_target(file_id), target)
163
164     def assertExecutable(self, branch, tree, path, executable):
165         file_id = tree.inventory.path2id(path)
166         branch.lock_read()
167         self.addCleanup(branch.unlock)
168         self.assertEqual(tree.is_executable(file_id), executable)
169
170     def assertRevisionRoot(self, revtree, path):
171         self.assertEqual(revtree.get_revision_id(),
172                          revtree.inventory.root.children[path].revision)
173
174
175 class TestImportToPackModify(TestCaseForGenericProcessor):
176
177     def file_command_iter(self, path, kind='file', content='aaa',
178         executable=False, to_kind=None, to_content='bbb', to_executable=None):
179         # Revno 1: create a file or symlink
180         # Revno 2: modify it
181         if to_kind is None:
182             to_kind = kind
183         if to_executable is None:
184             to_executable = executable
185         def command_list():
186             author = ['', 'bugs@a.com', time.time(), time.timezone]
187             committer = ['', 'elmer@a.com', time.time(), time.timezone]
188             def files_one():
189                 yield commands.FileModifyCommand(path, kind, executable,
190                         None, content)
191             yield commands.CommitCommand('head', '1', author,
192                 committer, "commit 1", None, [], files_one)
193             def files_two():
194                 yield commands.FileModifyCommand(path, to_kind, to_executable,
195                         None, to_content)
196             yield commands.CommitCommand('head', '2', author,
197                 committer, "commit 2", ":1", [], files_two)
198         return command_list
199
200     def test_modify_file_in_root(self):
201         handler, branch = self.get_handler()
202         path = 'a'
203         handler.process(self.file_command_iter(path))
204         revtree0, revtree1 = self.assertChanges(branch, 1,
205             expected_added=[(path,)])
206         revtree1, revtree2 = self.assertChanges(branch, 2,
207             expected_modified=[(path,)])
208         self.assertContent(branch, revtree1, path, "aaa")
209         self.assertContent(branch, revtree2, path, "bbb")
210         self.assertRevisionRoot(revtree1, path)
211         self.assertRevisionRoot(revtree2, path)
212
213     def test_modify_file_in_subdir(self):
214         handler, branch = self.get_handler()
215         path = 'a/a'
216         handler.process(self.file_command_iter(path))
217         revtree0, revtree1 = self.assertChanges(branch, 1,
218             expected_added=[('a',), (path,)])
219         revtree1, revtree2 = self.assertChanges(branch, 2,
220             expected_modified=[(path,)])
221         self.assertContent(branch, revtree1, path, "aaa")
222         self.assertContent(branch, revtree2, path, "bbb")
223
224     def test_modify_symlink_in_root(self):
225         handler, branch = self.get_handler()
226         path = 'a'
227         handler.process(self.file_command_iter(path, kind='symlink'))
228         revtree1, revtree2 = self.assertChanges(branch, 2,
229             expected_modified=[(path,)])
230         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
231         self.assertSymlinkTarget(branch, revtree2, path, "bbb")
232         self.assertRevisionRoot(revtree1, path)
233         self.assertRevisionRoot(revtree2, path)
234
235     def test_modify_symlink_in_subdir(self):
236         handler, branch = self.get_handler()
237         path = 'a/a'
238         handler.process(self.file_command_iter(path, kind='symlink'))
239         revtree0, revtree1 = self.assertChanges(branch, 1,
240             expected_added=[('a',), (path,)])
241         revtree1, revtree2 = self.assertChanges(branch, 2,
242             expected_modified=[(path,)])
243         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
244         self.assertSymlinkTarget(branch, revtree2, path, "bbb")
245
246     def test_modify_file_becomes_symlink(self):
247         handler, branch = self.get_handler()
248         path = 'a/a'
249         handler.process(self.file_command_iter(path,
250             kind='file', to_kind='symlink'))
251         revtree0, revtree1 = self.assertChanges(branch, 1,
252             expected_added=[('a',), (path,)])
253         revtree1, revtree2 = self.assertChanges(branch, 2,
254             expected_kind_changed=[(path, 'file', 'symlink')])
255         self.assertContent(branch, revtree1, path, "aaa")
256         self.assertSymlinkTarget(branch, revtree2, path, "bbb")
257
258     def test_modify_symlink_becomes_file(self):
259         handler, branch = self.get_handler()
260         path = 'a/a'
261         handler.process(self.file_command_iter(path,
262             kind='symlink', to_kind='file'))
263         revtree0, revtree1 = self.assertChanges(branch, 1,
264             expected_added=[('a',), (path,)])
265         revtree1, revtree2 = self.assertChanges(branch, 2,
266             expected_kind_changed=[(path, 'symlink', 'file')])
267         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
268         self.assertContent(branch, revtree2, path, "bbb")
269
270     def test_modify_file_now_executable(self):
271         handler, branch = self.get_handler()
272         path = 'a/a'
273         handler.process(self.file_command_iter(path,
274             executable=False, to_executable=True, to_content='aaa'))
275         revtree0, revtree1 = self.assertChanges(branch, 1,
276             expected_added=[('a',), (path,)])
277         revtree1, revtree2 = self.assertChanges(branch, 2,
278             expected_modified=[(path,)])
279         self.assertExecutable(branch, revtree1, path, False)
280         self.assertExecutable(branch, revtree2, path, True)
281
282     def test_modify_file_no_longer_executable(self):
283         handler, branch = self.get_handler()
284         path = 'a/a'
285         handler.process(self.file_command_iter(path,
286             executable=True, to_executable=False, to_content='aaa'))
287         revtree0, revtree1 = self.assertChanges(branch, 1,
288             expected_added=[('a',), (path,)])
289         revtree1, revtree2 = self.assertChanges(branch, 2,
290             expected_modified=[(path,)])
291         self.assertExecutable(branch, revtree1, path, True)
292         self.assertExecutable(branch, revtree2, path, False)
293
294
295 class TestImportToPackModifyTwice(TestCaseForGenericProcessor):
296     """This tests when the same file is modified twice in the one commit.
297     
298     Note: hg-fast-export produces data like this on occasions.
299     """
300
301     def file_command_iter(self, path, kind='file', content='aaa',
302         executable=False, to_kind=None, to_content='bbb', to_executable=None):
303         # Revno 1: create a file twice
304         if to_kind is None:
305             to_kind = kind
306         if to_executable is None:
307             to_executable = executable
308         def command_list():
309             author = ['', 'bugs@a.com', time.time(), time.timezone]
310             committer = ['', 'elmer@a.com', time.time(), time.timezone]
311             def files_one():
312                 yield commands.FileModifyCommand(path, kind, executable,
313                         None, content)
314                 yield commands.FileModifyCommand(path, to_kind, to_executable,
315                         None, to_content)
316             yield commands.CommitCommand('head', '1', author,
317                 committer, "commit 1", None, [], files_one)
318         return command_list
319
320     def test_modify_file_twice_in_root(self):
321         handler, branch = self.get_handler()
322         path = 'a'
323         handler.process(self.file_command_iter(path))
324         revtree0, revtree1 = self.assertChanges(branch, 1,
325             expected_added=[(path,)])
326         self.assertContent(branch, revtree1, path, "aaa")
327         self.assertRevisionRoot(revtree1, path)
328
329
330 class TestImportToPackModifyTricky(TestCaseForGenericProcessor):
331
332     def file_command_iter(self, path1, path2, kind='file'):
333         # Revno 1: create a file or symlink in a directory
334         # Revno 2: create a second file that implicitly deletes the
335         # first one because either:
336         # * the new file is a in directory with the old file name
337         # * the new file has the same name as the directory of the first
338         def command_list():
339             author = ['', 'bugs@a.com', time.time(), time.timezone]
340             committer = ['', 'elmer@a.com', time.time(), time.timezone]
341             def files_one():
342                 yield commands.FileModifyCommand(path1, kind, False,
343                         None, "aaa")
344             yield commands.CommitCommand('head', '1', author,
345                 committer, "commit 1", None, [], files_one)
346             def files_two():
347                 yield commands.FileModifyCommand(path2, kind, False,
348                         None, "bbb")
349             yield commands.CommitCommand('head', '2', author,
350                 committer, "commit 2", ":1", [], files_two)
351         return command_list
352
353
354     def test_modify_file_becomes_directory(self):
355         handler, branch = self.get_handler()
356         path1 = 'a/b'
357         path2 = 'a/b/c'
358         handler.process(self.file_command_iter(path1, path2))
359         revtree0, revtree1 = self.assertChanges(branch, 1,
360             expected_added=[('a',), (path1,)])
361         revtree1, revtree2 = self.assertChanges(branch, 2,
362             expected_added=[(path2,)],
363             expected_kind_changed=[(path1, 'file', 'directory')])
364         self.assertContent(branch, revtree1, path1, "aaa")
365         self.assertContent(branch, revtree2, path2, "bbb")
366
367     def test_modify_directory_becomes_file(self):
368         handler, branch = self.get_handler()
369         path1 = 'a/b/c'
370         path2 = 'a/b'
371         handler.process(self.file_command_iter(path1, path2))
372         revtree0, revtree1 = self.assertChanges(branch, 1,
373             expected_added=[('a',), ('a/b',), (path1,)])
374         revtree1, revtree2 = self.assertChanges(branch, 2,
375             expected_removed=[(path1,),],
376             expected_kind_changed=[(path2, 'directory', 'file')])
377         self.assertContent(branch, revtree1, path1, "aaa")
378         self.assertContent(branch, revtree2, path2, "bbb")
379
380     def test_modify_symlink_becomes_directory(self):
381         handler, branch = self.get_handler()
382         path1 = 'a/b'
383         path2 = 'a/b/c'
384         handler.process(self.file_command_iter(path1, path2, 'symlink'))
385         revtree0, revtree1 = self.assertChanges(branch, 1,
386             expected_added=[('a',), (path1,)])
387         revtree1, revtree2 = self.assertChanges(branch, 2,
388             expected_added=[(path2,)],
389             expected_kind_changed=[(path1, 'symlink', 'directory')])
390         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
391         self.assertSymlinkTarget(branch, revtree2, path2, "bbb")
392
393     def test_modify_directory_becomes_symlink(self):
394         handler, branch = self.get_handler()
395         path1 = 'a/b/c'
396         path2 = 'a/b'
397         handler.process(self.file_command_iter(path1, path2, 'symlink'))
398         revtree0, revtree1 = self.assertChanges(branch, 1,
399             expected_added=[('a',), ('a/b',), (path1,)])
400         revtree1, revtree2 = self.assertChanges(branch, 2,
401             expected_removed=[(path1,),],
402             expected_kind_changed=[(path2, 'directory', 'symlink')])
403         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
404         self.assertSymlinkTarget(branch, revtree2, path2, "bbb")
405
406
407 class TestImportToPackDelete(TestCaseForGenericProcessor):
408
409     def file_command_iter(self, path, kind='file'):
410         # Revno 1: create a file or symlink
411         # Revno 2: delete it
412         def command_list():
413             author = ['', 'bugs@a.com', time.time(), time.timezone]
414             committer = ['', 'elmer@a.com', time.time(), time.timezone]
415             def files_one():
416                 yield commands.FileModifyCommand(path, kind, False,
417                         None, "aaa")
418             yield commands.CommitCommand('head', '1', author,
419                 committer, "commit 1", None, [], files_one)
420             def files_two():
421                 yield commands.FileDeleteCommand(path)
422             yield commands.CommitCommand('head', '2', author,
423                 committer, "commit 2", ":1", [], files_two)
424         return command_list
425
426     def test_delete_file_in_root(self):
427         handler, branch = self.get_handler()
428         path = 'a'
429         handler.process(self.file_command_iter(path))
430         revtree0, revtree1 = self.assertChanges(branch, 1,
431             expected_added=[(path,)])
432         revtree1, revtree2 = self.assertChanges(branch, 2,
433             expected_removed=[(path,)])
434         self.assertContent(branch, revtree1, path, "aaa")
435         self.assertRevisionRoot(revtree1, path)
436
437     def test_delete_file_in_subdir(self):
438         handler, branch = self.get_handler()
439         path = 'a/a'
440         handler.process(self.file_command_iter(path))
441         revtree0, revtree1 = self.assertChanges(branch, 1,
442             expected_added=[('a',), (path,)])
443         revtree1, revtree2 = self.assertChanges(branch, 2,
444             expected_removed=[('a',), (path,)])
445         self.assertContent(branch, revtree1, path, "aaa")
446
447     def test_delete_symlink_in_root(self):
448         handler, branch = self.get_handler()
449         path = 'a'
450         handler.process(self.file_command_iter(path, kind='symlink'))
451         revtree1, revtree2 = self.assertChanges(branch, 2,
452             expected_removed=[(path,)])
453         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
454         self.assertRevisionRoot(revtree1, path)
455
456     def test_delete_symlink_in_subdir(self):
457         handler, branch = self.get_handler()
458         path = 'a/a'
459         handler.process(self.file_command_iter(path, kind='symlink'))
460         revtree0, revtree1 = self.assertChanges(branch, 1,
461             expected_added=[('a',), (path,)])
462         revtree1, revtree2 = self.assertChanges(branch, 2,
463             expected_removed=[('a',), (path,)])
464         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
465
466     def test_delete_file_in_deep_subdir(self):
467         handler, branch = self.get_handler()
468         path = 'a/b/c/d'
469         handler.process(self.file_command_iter(path))
470         revtree0, revtree1 = self.assertChanges(branch, 1,
471             expected_added=[('a',), ('a/b',), ('a/b/c',), (path,)])
472         revtree1, revtree2 = self.assertChanges(branch, 2,
473             expected_removed=[('a',), ('a/b',), ('a/b/c',), (path,)])
474         self.assertContent(branch, revtree1, path, "aaa")
475
476
477 class TestImportToPackDeleteNew(TestCaseForGenericProcessor):
478     """Test deletion of a newly added file."""
479
480     def file_command_iter(self, path, kind='file'):
481         # Revno 1: create a file or symlink then delete it
482         def command_list():
483             author = ['', 'bugs@a.com', time.time(), time.timezone]
484             committer = ['', 'elmer@a.com', time.time(), time.timezone]
485             def files_one():
486                 yield commands.FileModifyCommand(path, kind, False,
487                         None, "aaa")
488                 yield commands.FileDeleteCommand(path)
489             yield commands.CommitCommand('head', '1', author,
490                 committer, "commit 1", None, [], files_one)
491         return command_list
492
493     def test_delete_new_file_in_root(self):
494         handler, branch = self.get_handler()
495         path = 'a'
496         handler.process(self.file_command_iter(path))
497         revtree0, revtree1 = self.assertChanges(branch, 1,)
498
499     def test_delete_new_file_in_subdir(self):
500         handler, branch = self.get_handler()
501         path = 'a/a'
502         handler.process(self.file_command_iter(path))
503         revtree0, revtree1 = self.assertChanges(branch, 1,)
504
505     def test_delete_new_symlink_in_root(self):
506         handler, branch = self.get_handler()
507         path = 'a'
508         handler.process(self.file_command_iter(path, kind='symlink'))
509         revtree0, revtree1 = self.assertChanges(branch, 1,)
510
511     def test_delete_new_symlink_in_subdir(self):
512         handler, branch = self.get_handler()
513         path = 'a/a'
514         handler.process(self.file_command_iter(path, kind='symlink'))
515         revtree0, revtree1 = self.assertChanges(branch, 1,)
516
517     def test_delete_new_file_in_deep_subdir(self):
518         handler, branch = self.get_handler()
519         path = 'a/b/c/d'
520         handler.process(self.file_command_iter(path))
521         revtree0, revtree1 = self.assertChanges(branch, 1,)
522
523
524 class TestImportToPackDeleteThenAdd(TestCaseForGenericProcessor):
525     """Test delete followed by an add. Merges can cause this."""
526
527     def file_command_iter(self, path, kind='file', content='aaa',
528         executable=False, to_kind=None, to_content='bbb', to_executable=None):
529         # Revno 1: create a file or symlink
530         # Revno 2: delete it and add it
531         if to_kind is None:
532             to_kind = kind
533         if to_executable is None:
534             to_executable = executable
535         def command_list():
536             author = ['', 'bugs@a.com', time.time(), time.timezone]
537             committer = ['', 'elmer@a.com', time.time(), time.timezone]
538             def files_one():
539                 yield commands.FileModifyCommand(path, kind, executable,
540                         None, content)
541             yield commands.CommitCommand('head', '1', author,
542                 committer, "commit 1", None, [], files_one)
543             def files_two():
544                 yield commands.FileDeleteCommand(path)
545                 yield commands.FileModifyCommand(path, to_kind, to_executable,
546                         None, to_content)
547             yield commands.CommitCommand('head', '2', author,
548                 committer, "commit 2", ":1", [], files_two)
549         return command_list
550
551     def test_delete_then_add_file_in_root(self):
552         handler, branch = self.get_handler()
553         path = 'a'
554         handler.process(self.file_command_iter(path))
555         revtree0, revtree1 = self.assertChanges(branch, 1,
556             expected_added=[(path,)])
557         revtree1, revtree2 = self.assertChanges(branch, 2,
558             expected_removed=[(path,)],
559             expected_added=[(path,)])
560         self.assertContent(branch, revtree1, path, "aaa")
561         self.assertContent(branch, revtree2, path, "bbb")
562         self.assertRevisionRoot(revtree1, path)
563         self.assertRevisionRoot(revtree2, path)
564
565     def test_delete_then_add_file_in_subdir(self):
566         handler, branch = self.get_handler()
567         path = 'a/a'
568         handler.process(self.file_command_iter(path))
569         revtree0, revtree1 = self.assertChanges(branch, 1,
570             expected_added=[('a',), (path,)])
571         revtree1, revtree2 = self.assertChanges(branch, 2,
572             expected_removed=[(path,)],
573             expected_added=[(path,)])
574         self.assertContent(branch, revtree1, path, "aaa")
575         self.assertContent(branch, revtree2, path, "bbb")
576
577     def test_delete_then_add_symlink_in_root(self):
578         handler, branch = self.get_handler()
579         path = 'a'
580         handler.process(self.file_command_iter(path, kind='symlink'))
581         revtree1, revtree2 = self.assertChanges(branch, 2,
582             expected_removed=[(path,)],
583             expected_added=[(path,)])
584         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
585         self.assertSymlinkTarget(branch, revtree2, path, "bbb")
586         self.assertRevisionRoot(revtree1, path)
587         self.assertRevisionRoot(revtree2, path)
588
589     def test_delete_then_add_symlink_in_subdir(self):
590         handler, branch = self.get_handler()
591         path = 'a/a'
592         handler.process(self.file_command_iter(path, kind='symlink'))
593         revtree0, revtree1 = self.assertChanges(branch, 1,
594             expected_added=[('a',), (path,)])
595         revtree1, revtree2 = self.assertChanges(branch, 2,
596             expected_removed=[(path,)],
597             expected_added=[(path,)])
598         self.assertSymlinkTarget(branch, revtree1, path, "aaa")
599         self.assertSymlinkTarget(branch, revtree2, path, "bbb")
600
601
602 class TestImportToPackDeleteDirectory(TestCaseForGenericProcessor):
603
604     def file_command_iter(self, paths, dir):
605         # Revno 1: create multiple files
606         # Revno 2: delete a directory holding those files
607         def command_list():
608             author = ['', 'bugs@a.com', time.time(), time.timezone]
609             committer = ['', 'elmer@a.com', time.time(), time.timezone]
610             def files_one():
611                 for i, path in enumerate(paths):
612                     yield commands.FileModifyCommand(path, 'file', False,
613                             None, "aaa%d" % i)
614             yield commands.CommitCommand('head', '1', author,
615                 committer, "commit 1", None, [], files_one)
616             def files_two():
617                 yield commands.FileDeleteCommand(dir)
618             yield commands.CommitCommand('head', '2', author,
619                 committer, "commit 2", ":1", [], files_two)
620         return command_list
621
622     def test_delete_dir(self):
623         handler, branch = self.get_handler()
624         paths = ['a/b/c', 'a/b/d', 'a/b/e/f', 'a/g']
625         dir = 'a/b'
626         handler.process(self.file_command_iter(paths, dir))
627         revtree0, revtree1 = self.assertChanges(branch, 1,
628             expected_added=[
629                 ('a',), ('a/b',), ('a/b/c',),
630                 ('a/b/d',),
631                 ('a/b/e',), ('a/b/e/f',),
632                 ('a/g',),
633                 ])
634         revtree1, revtree2 = self.assertChanges(branch, 2,
635             expected_removed=[
636                 ('a/b',), ('a/b/c',),
637                 ('a/b/d',),
638                 ('a/b/e',), ('a/b/e/f',),
639                 ])
640
641
642 class TestImportToPackRename(TestCaseForGenericProcessor):
643
644     def get_command_iter(self, old_path, new_path, kind='file'):
645         # Revno 1: create a file or symlink
646         # Revno 2: rename it
647         def command_list():
648             author = ['', 'bugs@a.com', time.time(), time.timezone]
649             committer = ['', 'elmer@a.com', time.time(), time.timezone]
650             def files_one():
651                 yield commands.FileModifyCommand(old_path, kind, False,
652                         None, "aaa")
653             yield commands.CommitCommand('head', '1', author,
654                 committer, "commit 1", None, [], files_one)
655             def files_two():
656                 yield commands.FileRenameCommand(old_path, new_path)
657             yield commands.CommitCommand('head', '2', author,
658                 committer, "commit 2", ":1", [], files_two)
659         return command_list
660
661     def test_rename_file_in_root(self):
662         handler, branch = self.get_handler()
663         old_path = 'a'
664         new_path = 'b'
665         handler.process(self.get_command_iter(old_path, new_path))
666         revtree1, revtree2 = self.assertChanges(branch, 2,
667             expected_renamed=[(old_path, new_path)])
668         self.assertRevisionRoot(revtree1, old_path)
669         self.assertRevisionRoot(revtree2, new_path)
670
671     def test_rename_symlink_in_root(self):
672         handler, branch = self.get_handler()
673         old_path = 'a'
674         new_path = 'b'
675         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
676         revtree1, revtree2 = self.assertChanges(branch, 2,
677             expected_renamed=[(old_path, new_path)])
678         self.assertRevisionRoot(revtree1, old_path)
679         self.assertRevisionRoot(revtree2, new_path)
680
681     def test_rename_file_in_subdir(self):
682         handler, branch = self.get_handler()
683         old_path = 'a/a'
684         new_path = 'a/b'
685         handler.process(self.get_command_iter(old_path, new_path))
686         self.assertChanges(branch, 2, expected_renamed=[(old_path, new_path)])
687
688     def test_rename_symlink_in_subdir(self):
689         handler, branch = self.get_handler()
690         old_path = 'a/a'
691         new_path = 'a/b'
692         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
693         self.assertChanges(branch, 2, expected_renamed=[(old_path, new_path)])
694
695     def test_rename_file_to_new_dir(self):
696         handler, branch = self.get_handler()
697         old_path = 'a/a'
698         new_path = 'b/a'
699         handler.process(self.get_command_iter(old_path, new_path))
700         self.assertChanges(branch, 2,
701             expected_renamed=[(old_path, new_path)],
702             expected_added=[('b',)],
703             expected_removed=[('a',)])
704
705     def test_rename_symlink_to_new_dir(self):
706         handler, branch = self.get_handler()
707         old_path = 'a/a'
708         new_path = 'b/a'
709         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
710         self.assertChanges(branch, 2,
711             expected_renamed=[(old_path, new_path)],
712             expected_added=[('b',)],
713             expected_removed=[('a',)])
714
715
716 class TestImportToPackRenameNew(TestCaseForGenericProcessor):
717     """Test rename of a newly added file."""
718
719     def get_command_iter(self, old_path, new_path, kind='file'):
720         # Revno 1: create a file and rename it
721         def command_list():
722             author = ['', 'bugs@a.com', time.time(), time.timezone]
723             committer = ['', 'elmer@a.com', time.time(), time.timezone]
724             def files_one():
725                 yield commands.FileModifyCommand(old_path, kind, False,
726                         None, "aaa")
727                 yield commands.FileRenameCommand(old_path, new_path)
728             yield commands.CommitCommand('head', '1', author,
729                 committer, "commit 1", None, [], files_one)
730         return command_list
731
732     def test_rename_new_file_in_root(self):
733         handler, branch = self.get_handler()
734         old_path = 'a'
735         new_path = 'b'
736         handler.process(self.get_command_iter(old_path, new_path))
737         revtree0, revtree1 = self.assertChanges(branch, 1,
738             expected_added=[(new_path,)])
739         self.assertRevisionRoot(revtree1, new_path)
740
741     def test_rename_new_symlink_in_root(self):
742         handler, branch = self.get_handler()
743         old_path = 'a'
744         new_path = 'b'
745         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
746         revtree0, revtree1 = self.assertChanges(branch, 1,
747             expected_added=[(new_path,)])
748         self.assertRevisionRoot(revtree1, new_path)
749
750     def test_rename_new_file_in_subdir(self):
751         handler, branch = self.get_handler()
752         old_path = 'a/a'
753         new_path = 'a/b'
754         handler.process(self.get_command_iter(old_path, new_path))
755         revtree0, revtree1 = self.assertChanges(branch, 1,
756             expected_added=[('a',), (new_path,)])
757
758     def test_rename_new_symlink_in_subdir(self):
759         handler, branch = self.get_handler()
760         old_path = 'a/a'
761         new_path = 'a/b'
762         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
763         revtree0, revtree1 = self.assertChanges(branch, 1,
764             expected_added=[('a',), (new_path,)])
765
766
767 class TestImportToPackRenameToDeleted(TestCaseForGenericProcessor):
768     """Test rename to a destination path deleted in this commit."""
769
770     def get_command_iter(self, old_path, new_path, kind='file'):
771         # Revno 1: create two files
772         # Revno 2: delete one, rename the other one to that path
773         def command_list():
774             author = ['', 'bugs@a.com', time.time(), time.timezone]
775             committer = ['', 'elmer@a.com', time.time(), time.timezone]
776             def files_one():
777                 yield commands.FileModifyCommand(old_path, kind, False,
778                         None, "aaa")
779                 yield commands.FileModifyCommand(new_path, kind, False,
780                         None, "bbb")
781             yield commands.CommitCommand('head', '1', author,
782                 committer, "commit 1", None, [], files_one)
783             def files_two():
784                 yield commands.FileDeleteCommand(new_path)
785                 yield commands.FileRenameCommand(old_path, new_path)
786             yield commands.CommitCommand('head', '2', author,
787                 committer, "commit 2", ":1", [], files_two)
788         return command_list
789
790     def test_rename_to_deleted_file_in_root(self):
791         handler, branch = self.get_handler()
792         old_path = 'a'
793         new_path = 'b'
794         handler.process(self.get_command_iter(old_path, new_path))
795         revtree0, revtree1 = self.assertChanges(branch, 1,
796             expected_added=[(old_path,), (new_path,)])
797         revtree1, revtree2 = self.assertChanges(branch, 2,
798             expected_removed=[(new_path,)],
799             expected_renamed=[(old_path, new_path)])
800         self.assertContent(branch, revtree1, old_path, "aaa")
801         self.assertContent(branch, revtree1, new_path, "bbb")
802         self.assertContent(branch, revtree2, new_path, "aaa")
803         self.assertRevisionRoot(revtree1, old_path)
804         self.assertRevisionRoot(revtree1, new_path)
805
806     def test_rename_to_deleted_symlink_in_root(self):
807         handler, branch = self.get_handler()
808         old_path = 'a'
809         new_path = 'b'
810         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
811         revtree0, revtree1 = self.assertChanges(branch, 1,
812             expected_added=[(old_path,), (new_path,)])
813         revtree1, revtree2 = self.assertChanges(branch, 2,
814             expected_removed=[(new_path,)],
815             expected_renamed=[(old_path, new_path)])
816         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
817         self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
818         self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
819         self.assertRevisionRoot(revtree1, old_path)
820         self.assertRevisionRoot(revtree1, new_path)
821
822     def test_rename_to_deleted_file_in_subdir(self):
823         handler, branch = self.get_handler()
824         old_path = 'd/a'
825         new_path = 'd/b'
826         handler.process(self.get_command_iter(old_path, new_path))
827         revtree0, revtree1 = self.assertChanges(branch, 1,
828             expected_added=[('d',), (old_path,), (new_path,)])
829         revtree1, revtree2 = self.assertChanges(branch, 2,
830             expected_removed=[(new_path,)],
831             expected_renamed=[(old_path, new_path)])
832         self.assertContent(branch, revtree1, old_path, "aaa")
833         self.assertContent(branch, revtree1, new_path, "bbb")
834         self.assertContent(branch, revtree2, new_path, "aaa")
835
836     def test_rename_to_deleted_symlink_in_subdir(self):
837         handler, branch = self.get_handler()
838         old_path = 'd/a'
839         new_path = 'd/b'
840         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
841         revtree0, revtree1 = self.assertChanges(branch, 1,
842             expected_added=[('d',), (old_path,), (new_path,)])
843         revtree1, revtree2 = self.assertChanges(branch, 2,
844             expected_removed=[(new_path,)],
845             expected_renamed=[(old_path, new_path)])
846         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
847         self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
848         self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
849
850     def test_rename_to_deleted_file_in_new_dir(self):
851         handler, branch = self.get_handler()
852         old_path = 'd1/a'
853         new_path = 'd2/b'
854         handler.process(self.get_command_iter(old_path, new_path))
855         revtree0, revtree1 = self.assertChanges(branch, 1,
856             expected_added=[('d1',), (old_path,), ('d2',), (new_path,)])
857         revtree1, revtree2 = self.assertChanges(branch, 2,
858             expected_removed=[('d1',), (new_path,)],
859             expected_renamed=[(old_path, new_path)])
860         self.assertContent(branch, revtree1, old_path, "aaa")
861         self.assertContent(branch, revtree1, new_path, "bbb")
862         self.assertContent(branch, revtree2, new_path, "aaa")
863
864     def test_rename_to_deleted_symlink_in_new_dir(self):
865         handler, branch = self.get_handler()
866         old_path = 'd1/a'
867         new_path = 'd2/b'
868         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
869         revtree0, revtree1 = self.assertChanges(branch, 1,
870             expected_added=[('d1',), (old_path,), ('d2',), (new_path,)])
871         revtree1, revtree2 = self.assertChanges(branch, 2,
872             expected_removed=[('d1',), (new_path,)],
873             expected_renamed=[(old_path, new_path)])
874         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
875         self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
876         self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
877
878
879 class TestImportToPackRenameTricky(TestCaseForGenericProcessor):
880
881     def file_command_iter(self, path1, old_path2, new_path2, kind='file'):
882         # Revno 1: create two files or symlinks in a directory
883         # Revno 2: rename the second file so that it implicitly deletes the
884         # first one because either:
885         # * the new file is a in directory with the old file name
886         # * the new file has the same name as the directory of the first
887         def command_list():
888             author = ['', 'bugs@a.com', time.time(), time.timezone]
889             committer = ['', 'elmer@a.com', time.time(), time.timezone]
890             def files_one():
891                 yield commands.FileModifyCommand(path1, kind, False,
892                         None, "aaa")
893                 yield commands.FileModifyCommand(old_path2, kind, False,
894                         None, "bbb")
895             yield commands.CommitCommand('head', '1', author,
896                 committer, "commit 1", None, [], files_one)
897             def files_two():
898                 yield commands.FileRenameCommand(old_path2, new_path2)
899             yield commands.CommitCommand('head', '2', author,
900                 committer, "commit 2", ":1", [], files_two)
901         return command_list
902
903     def test_rename_file_becomes_directory(self):
904         handler, branch = self.get_handler()
905         old_path2 = 'foo'
906         path1     = 'a/b'
907         new_path2 = 'a/b/c'
908         handler.process(self.file_command_iter(path1, old_path2, new_path2))
909         revtree0, revtree1 = self.assertChanges(branch, 1,
910             expected_added=[('a',), (path1,), (old_path2,)])
911         revtree1, revtree2 = self.assertChanges(branch, 2,
912             expected_renamed=[(old_path2, new_path2)],
913             expected_kind_changed=[(path1, 'file', 'directory')])
914         self.assertContent(branch, revtree1, path1, "aaa")
915         self.assertContent(branch, revtree2, new_path2, "bbb")
916
917     def test_rename_directory_becomes_file(self):
918         handler, branch = self.get_handler()
919         old_path2 = 'foo'
920         path1     = 'a/b/c'
921         new_path2 = 'a/b'
922         handler.process(self.file_command_iter(path1, old_path2, new_path2))
923         revtree0, revtree1 = self.assertChanges(branch, 1,
924             expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
925         revtree1, revtree2 = self.assertChanges(branch, 2,
926             expected_renamed=[(old_path2, new_path2)],
927             expected_removed=[(path1,), (new_path2,)])
928         self.assertContent(branch, revtree1, path1, "aaa")
929         self.assertContent(branch, revtree2, new_path2, "bbb")
930
931     def test_rename_symlink_becomes_directory(self):
932         handler, branch = self.get_handler()
933         old_path2 = 'foo'
934         path1     = 'a/b'
935         new_path2 = 'a/b/c'
936         handler.process(self.file_command_iter(path1, old_path2, new_path2,
937             'symlink'))
938         revtree0, revtree1 = self.assertChanges(branch, 1,
939             expected_added=[('a',), (path1,), (old_path2,)])
940         revtree1, revtree2 = self.assertChanges(branch, 2,
941             expected_renamed=[(old_path2, new_path2)],
942             expected_kind_changed=[(path1, 'symlink', 'directory')])
943         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
944         self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
945
946     def test_rename_directory_becomes_symlink(self):
947         handler, branch = self.get_handler()
948         old_path2 = 'foo'
949         path1     = 'a/b/c'
950         new_path2 = 'a/b'
951         handler.process(self.file_command_iter(path1, old_path2, new_path2,
952             'symlink'))
953         revtree0, revtree1 = self.assertChanges(branch, 1,
954             expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
955         revtree1, revtree2 = self.assertChanges(branch, 2,
956             expected_renamed=[(old_path2, new_path2)],
957             expected_removed=[(path1,), (new_path2,)])
958         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
959         self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
960
961
962 class TestImportToPackCopy(TestCaseForGenericProcessor):
963
964     def file_command_iter(self, src_path, dest_path, kind='file'):
965         # Revno 1: create a file or symlink
966         # Revno 2: copy it
967         def command_list():
968             author = ['', 'bugs@a.com', time.time(), time.timezone]
969             committer = ['', 'elmer@a.com', time.time(), time.timezone]
970             def files_one():
971                 yield commands.FileModifyCommand(src_path, kind, False,
972                         None, "aaa")
973             yield commands.CommitCommand('head', '1', author,
974                 committer, "commit 1", None, [], files_one)
975             def files_two():
976                 yield commands.FileCopyCommand(src_path, dest_path)
977             yield commands.CommitCommand('head', '2', author,
978                 committer, "commit 2", ":1", [], files_two)
979         return command_list
980
981     def test_copy_file_in_root(self):
982         handler, branch = self.get_handler()
983         src_path = 'a'
984         dest_path = 'b'
985         handler.process(self.file_command_iter(src_path, dest_path))
986         revtree1, revtree2 = self.assertChanges(branch, 2,
987             expected_added=[(dest_path,)])
988         self.assertContent(branch, revtree1, src_path, "aaa")
989         self.assertContent(branch, revtree2, src_path, "aaa")
990         self.assertContent(branch, revtree2, dest_path, "aaa")
991         self.assertRevisionRoot(revtree1, src_path)
992         self.assertRevisionRoot(revtree2, dest_path)
993
994     def test_copy_file_in_subdir(self):
995         handler, branch = self.get_handler()
996         src_path = 'a/a'
997         dest_path = 'a/b'
998         handler.process(self.file_command_iter(src_path, dest_path))
999         revtree1, revtree2 = self.assertChanges(branch, 2,
1000             expected_added=[(dest_path,)])
1001         self.assertContent(branch, revtree1, src_path, "aaa")
1002         self.assertContent(branch, revtree2, src_path, "aaa")
1003         self.assertContent(branch, revtree2, dest_path, "aaa")
1004
1005     def test_copy_file_to_new_dir(self):
1006         handler, branch = self.get_handler()
1007         src_path = 'a/a'
1008         dest_path = 'b/a'
1009         handler.process(self.file_command_iter(src_path, dest_path))
1010         revtree1, revtree2 = self.assertChanges(branch, 2,
1011             expected_added=[('b',), (dest_path,)])
1012         self.assertContent(branch, revtree1, src_path, "aaa")
1013         self.assertContent(branch, revtree2, src_path, "aaa")
1014         self.assertContent(branch, revtree2, dest_path, "aaa")
1015
1016     def test_copy_symlink_in_root(self):
1017         handler, branch = self.get_handler()
1018         src_path = 'a'
1019         dest_path = 'b'
1020         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1021         revtree1, revtree2 = self.assertChanges(branch, 2,
1022             expected_added=[(dest_path,)])
1023         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1024         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1025         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1026         self.assertRevisionRoot(revtree1, src_path)
1027         self.assertRevisionRoot(revtree2, dest_path)
1028
1029     def test_copy_symlink_in_subdir(self):
1030         handler, branch = self.get_handler()
1031         src_path = 'a/a'
1032         dest_path = 'a/b'
1033         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1034         revtree1, revtree2 = self.assertChanges(branch, 2,
1035             expected_added=[(dest_path,)])
1036         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1037         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1038         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1039
1040     def test_copy_symlink_to_new_dir(self):
1041         handler, branch = self.get_handler()
1042         src_path = 'a/a'
1043         dest_path = 'b/a'
1044         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1045         revtree1, revtree2 = self.assertChanges(branch, 2,
1046             expected_added=[('b',), (dest_path,)])
1047         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1048         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1049         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1050
1051
1052 class TestImportToPackCopyNew(TestCaseForGenericProcessor):
1053     """Test copy of a newly added file."""
1054
1055     def file_command_iter(self, src_path, dest_path, kind='file'):
1056         # Revno 1: create a file or symlink and copy it
1057         def command_list():
1058             author = ['', 'bugs@a.com', time.time(), time.timezone]
1059             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1060             def files_one():
1061                 yield commands.FileModifyCommand(src_path, kind, False,
1062                         None, "aaa")
1063                 yield commands.FileCopyCommand(src_path, dest_path)
1064             yield commands.CommitCommand('head', '1', author,
1065                 committer, "commit 1", None, [], files_one)
1066         return command_list
1067
1068     def test_copy_new_file_in_root(self):
1069         handler, branch = self.get_handler()
1070         src_path = 'a'
1071         dest_path = 'b'
1072         handler.process(self.file_command_iter(src_path, dest_path))
1073         revtree0, revtree1 = self.assertChanges(branch, 1,
1074             expected_added=[(src_path,), (dest_path,)])
1075         self.assertContent(branch, revtree1, src_path, "aaa")
1076         self.assertContent(branch, revtree1, dest_path, "aaa")
1077         self.assertRevisionRoot(revtree1, src_path)
1078         self.assertRevisionRoot(revtree1, dest_path)
1079
1080     def test_copy_new_file_in_subdir(self):
1081         handler, branch = self.get_handler()
1082         src_path = 'a/a'
1083         dest_path = 'a/b'
1084         handler.process(self.file_command_iter(src_path, dest_path))
1085         revtree0, revtree1 = self.assertChanges(branch, 1,
1086             expected_added=[('a',), (src_path,), (dest_path,)])
1087         self.assertContent(branch, revtree1, src_path, "aaa")
1088         self.assertContent(branch, revtree1, dest_path, "aaa")
1089
1090     def test_copy_new_file_to_new_dir(self):
1091         handler, branch = self.get_handler()
1092         src_path = 'a/a'
1093         dest_path = 'b/a'
1094         handler.process(self.file_command_iter(src_path, dest_path))
1095         revtree0, revtree1 = self.assertChanges(branch, 1,
1096             expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
1097         self.assertContent(branch, revtree1, src_path, "aaa")
1098         self.assertContent(branch, revtree1, dest_path, "aaa")
1099
1100     def test_copy_new_symlink_in_root(self):
1101         handler, branch = self.get_handler()
1102         src_path = 'a'
1103         dest_path = 'b'
1104         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1105         revtree0, revtree1 = self.assertChanges(branch, 1,
1106             expected_added=[(src_path,), (dest_path,)])
1107         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1108         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1109         self.assertRevisionRoot(revtree1, src_path)
1110         self.assertRevisionRoot(revtree1, dest_path)
1111
1112     def test_copy_new_symlink_in_subdir(self):
1113         handler, branch = self.get_handler()
1114         src_path = 'a/a'
1115         dest_path = 'a/b'
1116         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1117         revtree0, revtree1 = self.assertChanges(branch, 1,
1118             expected_added=[('a',), (src_path,), (dest_path,)])
1119         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1120         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1121
1122     def test_copy_new_symlink_to_new_dir(self):
1123         handler, branch = self.get_handler()
1124         src_path = 'a/a'
1125         dest_path = 'b/a'
1126         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1127         revtree0, revtree1 = self.assertChanges(branch, 1,
1128             expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
1129         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1130         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1131
1132
1133 class TestImportToPackCopyToDeleted(TestCaseForGenericProcessor):
1134
1135     def file_command_iter(self, src_path, dest_path, kind='file'):
1136         # Revno 1: create two files or symlinks
1137         # Revno 2: delete one and copy the other one to its path
1138         def command_list():
1139             author = ['', 'bugs@a.com', time.time(), time.timezone]
1140             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1141             def files_one():
1142                 yield commands.FileModifyCommand(src_path, kind, False,
1143                         None, "aaa")
1144                 yield commands.FileModifyCommand(dest_path, kind, False,
1145                         None, "bbb")
1146             yield commands.CommitCommand('head', '1', author,
1147                 committer, "commit 1", None, [], files_one)
1148             def files_two():
1149                 yield commands.FileDeleteCommand(dest_path)
1150                 yield commands.FileCopyCommand(src_path, dest_path)
1151             yield commands.CommitCommand('head', '2', author,
1152                 committer, "commit 2", ":1", [], files_two)
1153         return command_list
1154
1155     def test_copy_to_deleted_file_in_root(self):
1156         handler, branch = self.get_handler()
1157         src_path = 'a'
1158         dest_path = 'b'
1159         handler.process(self.file_command_iter(src_path, dest_path))
1160         revtree0, revtree1 = self.assertChanges(branch, 1,
1161             expected_added=[(src_path,), (dest_path,)])
1162         revtree1, revtree2 = self.assertChanges(branch, 2,
1163             expected_removed=[(dest_path,)],
1164             expected_added=[(dest_path,)])
1165         self.assertContent(branch, revtree1, src_path, "aaa")
1166         self.assertContent(branch, revtree1, dest_path, "bbb")
1167         self.assertContent(branch, revtree2, src_path, "aaa")
1168         self.assertContent(branch, revtree2, dest_path, "aaa")
1169         self.assertRevisionRoot(revtree1, src_path)
1170         self.assertRevisionRoot(revtree1, dest_path)
1171
1172     def test_copy_to_deleted_symlink_in_root(self):
1173         handler, branch = self.get_handler()
1174         src_path = 'a'
1175         dest_path = 'b'
1176         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1177         revtree0, revtree1 = self.assertChanges(branch, 1,
1178             expected_added=[(src_path,), (dest_path,)])
1179         revtree1, revtree2 = self.assertChanges(branch, 2,
1180             expected_removed=[(dest_path,)],
1181             expected_added=[(dest_path,)])
1182         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1183         self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
1184         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1185         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1186         self.assertRevisionRoot(revtree1, src_path)
1187         self.assertRevisionRoot(revtree1, dest_path)
1188
1189     def test_copy_to_deleted_file_in_subdir(self):
1190         handler, branch = self.get_handler()
1191         src_path = 'd/a'
1192         dest_path = 'd/b'
1193         handler.process(self.file_command_iter(src_path, dest_path))
1194         revtree0, revtree1 = self.assertChanges(branch, 1,
1195             expected_added=[('d',), (src_path,), (dest_path,)])
1196         revtree1, revtree2 = self.assertChanges(branch, 2,
1197             expected_removed=[(dest_path,)],
1198             expected_added=[(dest_path,)])
1199         self.assertContent(branch, revtree1, src_path, "aaa")
1200         self.assertContent(branch, revtree1, dest_path, "bbb")
1201         self.assertContent(branch, revtree2, src_path, "aaa")
1202         self.assertContent(branch, revtree2, dest_path, "aaa")
1203
1204     def test_copy_to_deleted_symlink_in_subdir(self):
1205         handler, branch = self.get_handler()
1206         src_path = 'd/a'
1207         dest_path = 'd/b'
1208         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1209         revtree0, revtree1 = self.assertChanges(branch, 1,
1210             expected_added=[('d',), (src_path,), (dest_path,)])
1211         revtree1, revtree2 = self.assertChanges(branch, 2,
1212             expected_removed=[(dest_path,)],
1213             expected_added=[(dest_path,)])
1214         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1215         self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
1216         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1217         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1218
1219
1220 #class TestImportToPackCopyModified(TestCaseForGenericProcessor):
1221 #    """Test copy of a modified file."""
1222 #
1223 #    def file_command_iter(self, src_path, dest_path, kind='file'):
1224 #        # Revno 1: create a file or symlink
1225 #        # Revno 2: modify and copy it
1226 #        def command_list():
1227 #            author = ['', 'bugs@a.com', time.time(), time.timezone]
1228 #            committer = ['', 'elmer@a.com', time.time(), time.timezone]
1229 #            def files_one():
1230 #                yield commands.FileModifyCommand(src_path, kind, False,
1231 #                        None, "aaa")
1232 #            yield commands.CommitCommand('head', '1', author,
1233 #                committer, "commit 1", None, [], files_one)
1234 #            def files_two():
1235 #                yield commands.FileModifyCommand(src_path, kind, False,
1236 #                        None, "bbb")
1237 #                yield commands.FileCopyCommand(src_path, dest_path)
1238 #            yield commands.CommitCommand('head', '2', author,
1239 #                committer, "commit 2", ":1", [], files_two)
1240 #        return command_list
1241 #
1242 #    def test_copy_modified_file_in_root(self):
1243 #        handler, branch = self.get_handler()
1244 #        src_path = 'a'
1245 #        dest_path = 'b'
1246 #        handler.process(self.file_command_iter(src_path, dest_path))
1247 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1248 #            expected_modified=[(src_path,)],
1249 #            expected_added=[(dest_path,)])
1250 #        self.assertContent(branch, revtree1, src_path, "aaa")
1251 #        self.assertContent(branch, revtree2, src_path, "bbb")
1252 #        self.assertContent(branch, revtree2, dest_path, "bbb")
1253 #        self.assertRevisionRoot(revtree1, src_path)
1254 #        self.assertRevisionRoot(revtree2, dest_path)
1255 #
1256 #    def test_copy_modified_file_in_subdir(self):
1257 #        handler, branch = self.get_handler()
1258 #        src_path = 'a/a'
1259 #        dest_path = 'a/b'
1260 #        handler.process(self.file_command_iter(src_path, dest_path))
1261 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1262 #            expected_added=[(dest_path,)])
1263 #        self.assertContent(branch, revtree1, src_path, "aaa")
1264 #        self.assertContent(branch, revtree2, src_path, "aaa")
1265 #        self.assertContent(branch, revtree2, dest_path, "bbb")
1266 #
1267 #    def test_copy_modified_file_to_new_dir(self):
1268 #        handler, branch = self.get_handler()
1269 #        src_path = 'a/a'
1270 #        dest_path = 'b/a'
1271 #        handler.process(self.file_command_iter(src_path, dest_path))
1272 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1273 #            expected_added=[('b',), (dest_path,)])
1274 #        self.assertContent(branch, revtree1, src_path, "aaa")
1275 #        self.assertContent(branch, revtree2, src_path, "aaa")
1276 #        self.assertContent(branch, revtree2, dest_path, "bbb")
1277 #
1278 #    def test_copy_modified_symlink_in_root(self):
1279 #        handler, branch = self.get_handler()
1280 #        src_path = 'a'
1281 #        dest_path = 'b'
1282 #        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1283 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1284 #            expected_added=[(dest_path,)])
1285 #        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1286 #        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1287 #        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1288 #        self.assertRevisionRoot(revtree1, src_path)
1289 #        self.assertRevisionRoot(revtree2, dest_path)
1290 #
1291 #    def test_copy_modified_symlink_in_subdir(self):
1292 #        handler, branch = self.get_handler()
1293 #        src_path = 'a/a'
1294 #        dest_path = 'a/b'
1295 #        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1296 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1297 #            expected_added=[(dest_path,)])
1298 #        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1299 #        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1300 #        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1301 #
1302 #    def test_copy_modified_symlink_to_new_dir(self):
1303 #        handler, branch = self.get_handler()
1304 #        src_path = 'a/a'
1305 #        dest_path = 'b/a'
1306 #        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1307 #        revtree1, revtree2 = self.assertChanges(branch, 2,
1308 #            expected_added=[('b',), (dest_path,)])
1309 #        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1310 #        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1311 #        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1312
1313
1314 class TestImportToPackFileKinds(TestCaseForGenericProcessor):
1315
1316     def get_command_iter(self, path, kind, content):
1317         def command_list():
1318             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1319             def files_one():
1320                 yield commands.FileModifyCommand(path, kind, False,
1321                         None, content)
1322             yield commands.CommitCommand('head', '1', None,
1323                 committer, "commit 1", None, [], files_one)
1324         return command_list
1325
1326     def test_import_plainfile(self):
1327         handler, branch = self.get_handler()
1328         handler.process(self.get_command_iter('foo', 'file', 'aaa'))
1329
1330     def test_import_symlink(self):
1331         handler, branch = self.get_handler()
1332         handler.process(self.get_command_iter('foo', 'symlink', 'bar'))
1333
1334
1335 ### TODO: Parameterise tests rather than below hack
1336
1337 class TestImportToRichRootModify(TestImportToPackModify):
1338     branch_format = "1.9-rich-root"
1339
1340 class TestImportToRichRootModifyTwice(TestImportToPackModifyTwice):
1341     branch_format = "1.9-rich-root"
1342
1343 class TestImportToRichRootModifyTricky(TestImportToPackModifyTricky):
1344     branch_format = "1.9-rich-root"
1345
1346 class TestImportToRichRootDelete(TestImportToPackDelete):
1347     branch_format = "1.9-rich-root"
1348
1349 class TestImportToRichRootDeleteNew(TestImportToPackDeleteNew):
1350     branch_format = "1.9-rich-root"
1351
1352 class TestImportToRichRootDeleteThenAdd(TestImportToPackDeleteThenAdd):
1353     branch_format = "1.9-rich-root"
1354
1355 class TestImportToRichRootDeleteDirectory(TestImportToPackDeleteDirectory):
1356     branch_format = "1.9-rich-root"
1357
1358 class TestImportToRichRootRename(TestImportToPackRename):
1359     branch_format = "1.9-rich-root"
1360
1361 class TestImportToRichRootRenameNew(TestImportToPackRenameNew):
1362     branch_format = "1.9-rich-root"
1363
1364 class TestImportToRichRootRenameToDeleted(TestImportToPackRenameToDeleted):
1365     branch_format = "1.9-rich-root"
1366
1367 class TestImportToRichRootRenameTricky(TestImportToPackRenameTricky):
1368     branch_format = "1.9-rich-root"
1369
1370 class TestImportToRichRootCopy(TestImportToPackCopy):
1371     branch_format = "1.9-rich-root"
1372
1373 class TestImportToRichRootCopyNew(TestImportToPackCopyNew):
1374     branch_format = "1.9-rich-root"
1375
1376 class TestImportToRichRootCopyToDeleted(TestImportToPackCopyToDeleted):
1377     branch_format = "1.9-rich-root"
1378
1379 class TestImportToRichRootFileKinds(TestImportToPackFileKinds):
1380     branch_format = "1.9-rich-root"
1381
1382 try:
1383     from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2a
1384
1385     class TestImportToChkModify(TestImportToPackModify):
1386         branch_format = "2a"
1387
1388     class TestImportToChkModifyTwice(TestImportToPackModifyTwice):
1389         branch_format = "2a"
1390
1391     class TestImportToChkModifyTricky(TestImportToPackModifyTricky):
1392         branch_format = "2a"
1393
1394     class TestImportToChkDelete(TestImportToPackDelete):
1395         branch_format = "2a"
1396
1397     class TestImportToChkDeleteNew(TestImportToPackDeleteNew):
1398         branch_format = "2a"
1399
1400     class TestImportToChkDeleteThenAdd(TestImportToPackDeleteThenAdd):
1401         branch_format = "2a"
1402
1403     class TestImportToChkDeleteDirectory(TestImportToPackDeleteDirectory):
1404         branch_format = "2a"
1405
1406     class TestImportToChkRename(TestImportToPackRename):
1407         branch_format = "2a"
1408
1409     class TestImportToChkRenameNew(TestImportToPackRenameNew):
1410         branch_format = "2a"
1411
1412     class TestImportToChkRenameToDeleted(TestImportToPackRenameToDeleted):
1413         branch_format = "2a"
1414
1415     class TestImportToChkRenameTricky(TestImportToPackRenameTricky):
1416         branch_format = "2a"
1417
1418     class TestImportToChkCopy(TestImportToPackCopy):
1419         branch_format = "2a"
1420
1421     class TestImportToChkCopyNew(TestImportToPackCopyNew):
1422         branch_format = "2a"
1423
1424     class TestImportToChkCopyToDeleted(TestImportToPackCopyToDeleted):
1425         branch_format = "2a"
1426
1427     class TestImportToChkFileKinds(TestImportToPackFileKinds):
1428         branch_format = "2a"
1429
1430 except ImportError:
1431     pass