Handle copy of a file/symlink already modified in this commit
[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 TestImportToPackRenameModified(TestCaseForGenericProcessor):
880     """Test rename of a path previously modified in this commit."""
881
882     def get_command_iter(self, old_path, new_path, kind='file'):
883         # Revno 1: create a file or symlink
884         # Revno 2: modify then rename it
885         def command_list():
886             author = ['', 'bugs@a.com', time.time(), time.timezone]
887             committer = ['', 'elmer@a.com', time.time(), time.timezone]
888             def files_one():
889                 yield commands.FileModifyCommand(old_path, kind, False,
890                         None, "aaa")
891             yield commands.CommitCommand('head', '1', author,
892                 committer, "commit 1", None, [], files_one)
893             def files_two():
894                 yield commands.FileModifyCommand(old_path, kind, False,
895                         None, "bbb")
896                 yield commands.FileRenameCommand(old_path, new_path)
897             yield commands.CommitCommand('head', '2', author,
898                 committer, "commit 2", ":1", [], files_two)
899         return command_list
900
901     def test_rename_of_modified_file_in_root(self):
902         handler, branch = self.get_handler()
903         old_path = 'a'
904         new_path = 'b'
905         handler.process(self.get_command_iter(old_path, new_path))
906         revtree0, revtree1 = self.assertChanges(branch, 1,
907             expected_added=[(old_path,)])
908         # Note: the delta doesn't show the modification?
909         # The actual new content is validated in the assertions following.
910         revtree1, revtree2 = self.assertChanges(branch, 2,
911             expected_renamed=[(old_path, new_path)])
912         self.assertContent(branch, revtree1, old_path, "aaa")
913         self.assertContent(branch, revtree2, new_path, "bbb")
914         self.assertRevisionRoot(revtree1, old_path)
915         self.assertRevisionRoot(revtree2, new_path)
916
917     def test_rename_of_modified_symlink_in_root(self):
918         handler, branch = self.get_handler()
919         old_path = 'a'
920         new_path = 'b'
921         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
922         revtree0, revtree1 = self.assertChanges(branch, 1,
923             expected_added=[(old_path,)])
924         # Note: the delta doesn't show the modification?
925         # The actual new content is validated in the assertions following.
926         revtree1, revtree2 = self.assertChanges(branch, 2,
927             expected_renamed=[(old_path, new_path)])
928         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
929         self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
930         self.assertRevisionRoot(revtree1, old_path)
931         self.assertRevisionRoot(revtree2, new_path)
932
933     def test_rename_of_modified_file_in_subdir(self):
934         handler, branch = self.get_handler()
935         old_path = 'd/a'
936         new_path = 'd/b'
937         handler.process(self.get_command_iter(old_path, new_path))
938         revtree0, revtree1 = self.assertChanges(branch, 1,
939             expected_added=[('d',), (old_path,)])
940         # Note: the delta doesn't show the modification?
941         # The actual new content is validated in the assertions following.
942         revtree1, revtree2 = self.assertChanges(branch, 2,
943             expected_renamed=[(old_path, new_path)])
944         self.assertContent(branch, revtree1, old_path, "aaa")
945         self.assertContent(branch, revtree2, new_path, "bbb")
946
947     def test_rename_of_modified_symlink_in_subdir(self):
948         handler, branch = self.get_handler()
949         old_path = 'd/a'
950         new_path = 'd/b'
951         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
952         revtree0, revtree1 = self.assertChanges(branch, 1,
953             expected_added=[('d',), (old_path,)])
954         # Note: the delta doesn't show the modification?
955         # The actual new content is validated in the assertions following.
956         revtree1, revtree2 = self.assertChanges(branch, 2,
957             expected_renamed=[(old_path, new_path)])
958         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
959         self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
960
961     def test_rename_of_modified_file_to_new_dir(self):
962         handler, branch = self.get_handler()
963         old_path = 'd1/a'
964         new_path = 'd2/b'
965         handler.process(self.get_command_iter(old_path, new_path))
966         revtree0, revtree1 = self.assertChanges(branch, 1,
967             expected_added=[('d1',), (old_path,)])
968         # Note: the delta doesn't show the modification?
969         # The actual new content is validated in the assertions following.
970         revtree1, revtree2 = self.assertChanges(branch, 2,
971             expected_renamed=[(old_path, new_path)],
972             expected_added=[('d2',)],
973             expected_removed=[('d1',)])
974         self.assertContent(branch, revtree1, old_path, "aaa")
975         self.assertContent(branch, revtree2, new_path, "bbb")
976
977     def test_rename_of_modified_symlink_to_new_dir(self):
978         handler, branch = self.get_handler()
979         old_path = 'd1/a'
980         new_path = 'd2/b'
981         handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
982         revtree0, revtree1 = self.assertChanges(branch, 1,
983             expected_added=[('d1',), (old_path,)])
984         # Note: the delta doesn't show the modification?
985         # The actual new content is validated in the assertions following.
986         revtree1, revtree2 = self.assertChanges(branch, 2,
987             expected_renamed=[(old_path, new_path)],
988             expected_added=[('d2',)],
989             expected_removed=[('d1',)])
990         self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
991         self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
992
993
994 class TestImportToPackRenameTricky(TestCaseForGenericProcessor):
995
996     def file_command_iter(self, path1, old_path2, new_path2, kind='file'):
997         # Revno 1: create two files or symlinks in a directory
998         # Revno 2: rename the second file so that it implicitly deletes the
999         # first one because either:
1000         # * the new file is a in directory with the old file name
1001         # * the new file has the same name as the directory of the first
1002         def command_list():
1003             author = ['', 'bugs@a.com', time.time(), time.timezone]
1004             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1005             def files_one():
1006                 yield commands.FileModifyCommand(path1, kind, False,
1007                         None, "aaa")
1008                 yield commands.FileModifyCommand(old_path2, kind, False,
1009                         None, "bbb")
1010             yield commands.CommitCommand('head', '1', author,
1011                 committer, "commit 1", None, [], files_one)
1012             def files_two():
1013                 yield commands.FileRenameCommand(old_path2, new_path2)
1014             yield commands.CommitCommand('head', '2', author,
1015                 committer, "commit 2", ":1", [], files_two)
1016         return command_list
1017
1018     def test_rename_file_becomes_directory(self):
1019         handler, branch = self.get_handler()
1020         old_path2 = 'foo'
1021         path1     = 'a/b'
1022         new_path2 = 'a/b/c'
1023         handler.process(self.file_command_iter(path1, old_path2, new_path2))
1024         revtree0, revtree1 = self.assertChanges(branch, 1,
1025             expected_added=[('a',), (path1,), (old_path2,)])
1026         revtree1, revtree2 = self.assertChanges(branch, 2,
1027             expected_renamed=[(old_path2, new_path2)],
1028             expected_kind_changed=[(path1, 'file', 'directory')])
1029         self.assertContent(branch, revtree1, path1, "aaa")
1030         self.assertContent(branch, revtree2, new_path2, "bbb")
1031
1032     def test_rename_directory_becomes_file(self):
1033         handler, branch = self.get_handler()
1034         old_path2 = 'foo'
1035         path1     = 'a/b/c'
1036         new_path2 = 'a/b'
1037         handler.process(self.file_command_iter(path1, old_path2, new_path2))
1038         revtree0, revtree1 = self.assertChanges(branch, 1,
1039             expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
1040         revtree1, revtree2 = self.assertChanges(branch, 2,
1041             expected_renamed=[(old_path2, new_path2)],
1042             expected_removed=[(path1,), (new_path2,)])
1043         self.assertContent(branch, revtree1, path1, "aaa")
1044         self.assertContent(branch, revtree2, new_path2, "bbb")
1045
1046     def test_rename_symlink_becomes_directory(self):
1047         handler, branch = self.get_handler()
1048         old_path2 = 'foo'
1049         path1     = 'a/b'
1050         new_path2 = 'a/b/c'
1051         handler.process(self.file_command_iter(path1, old_path2, new_path2,
1052             'symlink'))
1053         revtree0, revtree1 = self.assertChanges(branch, 1,
1054             expected_added=[('a',), (path1,), (old_path2,)])
1055         revtree1, revtree2 = self.assertChanges(branch, 2,
1056             expected_renamed=[(old_path2, new_path2)],
1057             expected_kind_changed=[(path1, 'symlink', 'directory')])
1058         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
1059         self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
1060
1061     def test_rename_directory_becomes_symlink(self):
1062         handler, branch = self.get_handler()
1063         old_path2 = 'foo'
1064         path1     = 'a/b/c'
1065         new_path2 = 'a/b'
1066         handler.process(self.file_command_iter(path1, old_path2, new_path2,
1067             'symlink'))
1068         revtree0, revtree1 = self.assertChanges(branch, 1,
1069             expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
1070         revtree1, revtree2 = self.assertChanges(branch, 2,
1071             expected_renamed=[(old_path2, new_path2)],
1072             expected_removed=[(path1,), (new_path2,)])
1073         self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
1074         self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
1075
1076
1077 class TestImportToPackCopy(TestCaseForGenericProcessor):
1078
1079     def file_command_iter(self, src_path, dest_path, kind='file'):
1080         # Revno 1: create a file or symlink
1081         # Revno 2: copy it
1082         def command_list():
1083             author = ['', 'bugs@a.com', time.time(), time.timezone]
1084             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1085             def files_one():
1086                 yield commands.FileModifyCommand(src_path, kind, False,
1087                         None, "aaa")
1088             yield commands.CommitCommand('head', '1', author,
1089                 committer, "commit 1", None, [], files_one)
1090             def files_two():
1091                 yield commands.FileCopyCommand(src_path, dest_path)
1092             yield commands.CommitCommand('head', '2', author,
1093                 committer, "commit 2", ":1", [], files_two)
1094         return command_list
1095
1096     def test_copy_file_in_root(self):
1097         handler, branch = self.get_handler()
1098         src_path = 'a'
1099         dest_path = 'b'
1100         handler.process(self.file_command_iter(src_path, dest_path))
1101         revtree1, revtree2 = self.assertChanges(branch, 2,
1102             expected_added=[(dest_path,)])
1103         self.assertContent(branch, revtree1, src_path, "aaa")
1104         self.assertContent(branch, revtree2, src_path, "aaa")
1105         self.assertContent(branch, revtree2, dest_path, "aaa")
1106         self.assertRevisionRoot(revtree1, src_path)
1107         self.assertRevisionRoot(revtree2, dest_path)
1108
1109     def test_copy_file_in_subdir(self):
1110         handler, branch = self.get_handler()
1111         src_path = 'a/a'
1112         dest_path = 'a/b'
1113         handler.process(self.file_command_iter(src_path, dest_path))
1114         revtree1, revtree2 = self.assertChanges(branch, 2,
1115             expected_added=[(dest_path,)])
1116         self.assertContent(branch, revtree1, src_path, "aaa")
1117         self.assertContent(branch, revtree2, src_path, "aaa")
1118         self.assertContent(branch, revtree2, dest_path, "aaa")
1119
1120     def test_copy_file_to_new_dir(self):
1121         handler, branch = self.get_handler()
1122         src_path = 'a/a'
1123         dest_path = 'b/a'
1124         handler.process(self.file_command_iter(src_path, dest_path))
1125         revtree1, revtree2 = self.assertChanges(branch, 2,
1126             expected_added=[('b',), (dest_path,)])
1127         self.assertContent(branch, revtree1, src_path, "aaa")
1128         self.assertContent(branch, revtree2, src_path, "aaa")
1129         self.assertContent(branch, revtree2, dest_path, "aaa")
1130
1131     def test_copy_symlink_in_root(self):
1132         handler, branch = self.get_handler()
1133         src_path = 'a'
1134         dest_path = 'b'
1135         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1136         revtree1, revtree2 = self.assertChanges(branch, 2,
1137             expected_added=[(dest_path,)])
1138         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1139         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1140         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1141         self.assertRevisionRoot(revtree1, src_path)
1142         self.assertRevisionRoot(revtree2, dest_path)
1143
1144     def test_copy_symlink_in_subdir(self):
1145         handler, branch = self.get_handler()
1146         src_path = 'a/a'
1147         dest_path = 'a/b'
1148         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1149         revtree1, revtree2 = self.assertChanges(branch, 2,
1150             expected_added=[(dest_path,)])
1151         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1152         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1153         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1154
1155     def test_copy_symlink_to_new_dir(self):
1156         handler, branch = self.get_handler()
1157         src_path = 'a/a'
1158         dest_path = 'b/a'
1159         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1160         revtree1, revtree2 = self.assertChanges(branch, 2,
1161             expected_added=[('b',), (dest_path,)])
1162         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1163         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1164         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1165
1166
1167 class TestImportToPackCopyNew(TestCaseForGenericProcessor):
1168     """Test copy of a newly added file."""
1169
1170     def file_command_iter(self, src_path, dest_path, kind='file'):
1171         # Revno 1: create a file or symlink and copy it
1172         def command_list():
1173             author = ['', 'bugs@a.com', time.time(), time.timezone]
1174             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1175             def files_one():
1176                 yield commands.FileModifyCommand(src_path, kind, False,
1177                         None, "aaa")
1178                 yield commands.FileCopyCommand(src_path, dest_path)
1179             yield commands.CommitCommand('head', '1', author,
1180                 committer, "commit 1", None, [], files_one)
1181         return command_list
1182
1183     def test_copy_new_file_in_root(self):
1184         handler, branch = self.get_handler()
1185         src_path = 'a'
1186         dest_path = 'b'
1187         handler.process(self.file_command_iter(src_path, dest_path))
1188         revtree0, revtree1 = self.assertChanges(branch, 1,
1189             expected_added=[(src_path,), (dest_path,)])
1190         self.assertContent(branch, revtree1, src_path, "aaa")
1191         self.assertContent(branch, revtree1, dest_path, "aaa")
1192         self.assertRevisionRoot(revtree1, src_path)
1193         self.assertRevisionRoot(revtree1, dest_path)
1194
1195     def test_copy_new_file_in_subdir(self):
1196         handler, branch = self.get_handler()
1197         src_path = 'a/a'
1198         dest_path = 'a/b'
1199         handler.process(self.file_command_iter(src_path, dest_path))
1200         revtree0, revtree1 = self.assertChanges(branch, 1,
1201             expected_added=[('a',), (src_path,), (dest_path,)])
1202         self.assertContent(branch, revtree1, src_path, "aaa")
1203         self.assertContent(branch, revtree1, dest_path, "aaa")
1204
1205     def test_copy_new_file_to_new_dir(self):
1206         handler, branch = self.get_handler()
1207         src_path = 'a/a'
1208         dest_path = 'b/a'
1209         handler.process(self.file_command_iter(src_path, dest_path))
1210         revtree0, revtree1 = self.assertChanges(branch, 1,
1211             expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
1212         self.assertContent(branch, revtree1, src_path, "aaa")
1213         self.assertContent(branch, revtree1, dest_path, "aaa")
1214
1215     def test_copy_new_symlink_in_root(self):
1216         handler, branch = self.get_handler()
1217         src_path = 'a'
1218         dest_path = 'b'
1219         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1220         revtree0, revtree1 = self.assertChanges(branch, 1,
1221             expected_added=[(src_path,), (dest_path,)])
1222         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1223         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1224         self.assertRevisionRoot(revtree1, src_path)
1225         self.assertRevisionRoot(revtree1, dest_path)
1226
1227     def test_copy_new_symlink_in_subdir(self):
1228         handler, branch = self.get_handler()
1229         src_path = 'a/a'
1230         dest_path = 'a/b'
1231         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1232         revtree0, revtree1 = self.assertChanges(branch, 1,
1233             expected_added=[('a',), (src_path,), (dest_path,)])
1234         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1235         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1236
1237     def test_copy_new_symlink_to_new_dir(self):
1238         handler, branch = self.get_handler()
1239         src_path = 'a/a'
1240         dest_path = 'b/a'
1241         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1242         revtree0, revtree1 = self.assertChanges(branch, 1,
1243             expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
1244         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1245         self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
1246
1247
1248 class TestImportToPackCopyToDeleted(TestCaseForGenericProcessor):
1249
1250     def file_command_iter(self, src_path, dest_path, kind='file'):
1251         # Revno 1: create two files or symlinks
1252         # Revno 2: delete one and copy the other one to its path
1253         def command_list():
1254             author = ['', 'bugs@a.com', time.time(), time.timezone]
1255             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1256             def files_one():
1257                 yield commands.FileModifyCommand(src_path, kind, False,
1258                         None, "aaa")
1259                 yield commands.FileModifyCommand(dest_path, kind, False,
1260                         None, "bbb")
1261             yield commands.CommitCommand('head', '1', author,
1262                 committer, "commit 1", None, [], files_one)
1263             def files_two():
1264                 yield commands.FileDeleteCommand(dest_path)
1265                 yield commands.FileCopyCommand(src_path, dest_path)
1266             yield commands.CommitCommand('head', '2', author,
1267                 committer, "commit 2", ":1", [], files_two)
1268         return command_list
1269
1270     def test_copy_to_deleted_file_in_root(self):
1271         handler, branch = self.get_handler()
1272         src_path = 'a'
1273         dest_path = 'b'
1274         handler.process(self.file_command_iter(src_path, dest_path))
1275         revtree0, revtree1 = self.assertChanges(branch, 1,
1276             expected_added=[(src_path,), (dest_path,)])
1277         revtree1, revtree2 = self.assertChanges(branch, 2,
1278             expected_removed=[(dest_path,)],
1279             expected_added=[(dest_path,)])
1280         self.assertContent(branch, revtree1, src_path, "aaa")
1281         self.assertContent(branch, revtree1, dest_path, "bbb")
1282         self.assertContent(branch, revtree2, src_path, "aaa")
1283         self.assertContent(branch, revtree2, dest_path, "aaa")
1284         self.assertRevisionRoot(revtree1, src_path)
1285         self.assertRevisionRoot(revtree1, dest_path)
1286
1287     def test_copy_to_deleted_symlink_in_root(self):
1288         handler, branch = self.get_handler()
1289         src_path = 'a'
1290         dest_path = 'b'
1291         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1292         revtree0, revtree1 = self.assertChanges(branch, 1,
1293             expected_added=[(src_path,), (dest_path,)])
1294         revtree1, revtree2 = self.assertChanges(branch, 2,
1295             expected_removed=[(dest_path,)],
1296             expected_added=[(dest_path,)])
1297         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1298         self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
1299         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1300         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1301         self.assertRevisionRoot(revtree1, src_path)
1302         self.assertRevisionRoot(revtree1, dest_path)
1303
1304     def test_copy_to_deleted_file_in_subdir(self):
1305         handler, branch = self.get_handler()
1306         src_path = 'd/a'
1307         dest_path = 'd/b'
1308         handler.process(self.file_command_iter(src_path, dest_path))
1309         revtree0, revtree1 = self.assertChanges(branch, 1,
1310             expected_added=[('d',), (src_path,), (dest_path,)])
1311         revtree1, revtree2 = self.assertChanges(branch, 2,
1312             expected_removed=[(dest_path,)],
1313             expected_added=[(dest_path,)])
1314         self.assertContent(branch, revtree1, src_path, "aaa")
1315         self.assertContent(branch, revtree1, dest_path, "bbb")
1316         self.assertContent(branch, revtree2, src_path, "aaa")
1317         self.assertContent(branch, revtree2, dest_path, "aaa")
1318
1319     def test_copy_to_deleted_symlink_in_subdir(self):
1320         handler, branch = self.get_handler()
1321         src_path = 'd/a'
1322         dest_path = 'd/b'
1323         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1324         revtree0, revtree1 = self.assertChanges(branch, 1,
1325             expected_added=[('d',), (src_path,), (dest_path,)])
1326         revtree1, revtree2 = self.assertChanges(branch, 2,
1327             expected_removed=[(dest_path,)],
1328             expected_added=[(dest_path,)])
1329         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1330         self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
1331         self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
1332         self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
1333
1334
1335 class TestImportToPackCopyModified(TestCaseForGenericProcessor):
1336     """Test copy of file/symlink already modified in this commit."""
1337
1338     def file_command_iter(self, src_path, dest_path, kind='file'):
1339         # Revno 1: create a file or symlink
1340         # Revno 2: modify and copy it
1341         def command_list():
1342             author = ['', 'bugs@a.com', time.time(), time.timezone]
1343             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1344             def files_one():
1345                 yield commands.FileModifyCommand(src_path, kind, False,
1346                         None, "aaa")
1347             yield commands.CommitCommand('head', '1', author,
1348                 committer, "commit 1", None, [], files_one)
1349             def files_two():
1350                 yield commands.FileModifyCommand(src_path, kind, False,
1351                         None, "bbb")
1352                 yield commands.FileCopyCommand(src_path, dest_path)
1353             yield commands.CommitCommand('head', '2', author,
1354                 committer, "commit 2", ":1", [], files_two)
1355         return command_list
1356
1357     def test_copy_of_modified_file_in_root(self):
1358         handler, branch = self.get_handler()
1359         src_path = 'a'
1360         dest_path = 'b'
1361         handler.process(self.file_command_iter(src_path, dest_path))
1362         revtree1, revtree2 = self.assertChanges(branch, 2,
1363             expected_modified=[(src_path,)],
1364             expected_added=[(dest_path,)])
1365         self.assertContent(branch, revtree1, src_path, "aaa")
1366         self.assertContent(branch, revtree2, src_path, "bbb")
1367         self.assertContent(branch, revtree2, dest_path, "bbb")
1368         self.assertRevisionRoot(revtree1, src_path)
1369         self.assertRevisionRoot(revtree2, dest_path)
1370
1371     def test_copy_of_modified_file_in_subdir(self):
1372         handler, branch = self.get_handler()
1373         src_path = 'd/a'
1374         dest_path = 'd/b'
1375         handler.process(self.file_command_iter(src_path, dest_path))
1376         revtree1, revtree2 = self.assertChanges(branch, 2,
1377             expected_modified=[(src_path,)],
1378             expected_added=[(dest_path,)])
1379         self.assertContent(branch, revtree1, src_path, "aaa")
1380         self.assertContent(branch, revtree2, src_path, "bbb")
1381         self.assertContent(branch, revtree2, dest_path, "bbb")
1382
1383     def test_copy_of_modified_file_to_new_dir(self):
1384         handler, branch = self.get_handler()
1385         src_path = 'd1/a'
1386         dest_path = 'd2/a'
1387         handler.process(self.file_command_iter(src_path, dest_path))
1388         revtree1, revtree2 = self.assertChanges(branch, 2,
1389             expected_modified=[(src_path,)],
1390             expected_added=[('d2',), (dest_path,)])
1391         self.assertContent(branch, revtree1, src_path, "aaa")
1392         self.assertContent(branch, revtree2, src_path, "bbb")
1393         self.assertContent(branch, revtree2, dest_path, "bbb")
1394
1395     def test_copy_of_modified_symlink_in_root(self):
1396         handler, branch = self.get_handler()
1397         src_path = 'a'
1398         dest_path = 'b'
1399         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1400         revtree1, revtree2 = self.assertChanges(branch, 2,
1401             expected_modified=[(src_path,)],
1402             expected_added=[(dest_path,)])
1403         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1404         self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
1405         self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1406         self.assertRevisionRoot(revtree1, src_path)
1407         self.assertRevisionRoot(revtree2, dest_path)
1408
1409     def test_copy_of_modified_symlink_in_subdir(self):
1410         handler, branch = self.get_handler()
1411         src_path = 'd/a'
1412         dest_path = 'd/b'
1413         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1414         revtree1, revtree2 = self.assertChanges(branch, 2,
1415             expected_modified=[(src_path,)],
1416             expected_added=[(dest_path,)])
1417         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1418         self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
1419         self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1420
1421     def test_copy_of_modified_symlink_to_new_dir(self):
1422         handler, branch = self.get_handler()
1423         src_path = 'd1/a'
1424         dest_path = 'd2/a'
1425         handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
1426         revtree1, revtree2 = self.assertChanges(branch, 2,
1427             expected_modified=[(src_path,)],
1428             expected_added=[('d2',), (dest_path,)])
1429         self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
1430         self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
1431         self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
1432
1433
1434 class TestImportToPackFileKinds(TestCaseForGenericProcessor):
1435
1436     def get_command_iter(self, path, kind, content):
1437         def command_list():
1438             committer = ['', 'elmer@a.com', time.time(), time.timezone]
1439             def files_one():
1440                 yield commands.FileModifyCommand(path, kind, False,
1441                         None, content)
1442             yield commands.CommitCommand('head', '1', None,
1443                 committer, "commit 1", None, [], files_one)
1444         return command_list
1445
1446     def test_import_plainfile(self):
1447         handler, branch = self.get_handler()
1448         handler.process(self.get_command_iter('foo', 'file', 'aaa'))
1449
1450     def test_import_symlink(self):
1451         handler, branch = self.get_handler()
1452         handler.process(self.get_command_iter('foo', 'symlink', 'bar'))
1453
1454
1455 ### TODO: Parameterise tests rather than below hack
1456
1457 class TestImportToRichRootModify(TestImportToPackModify):
1458     branch_format = "1.9-rich-root"
1459
1460 class TestImportToRichRootModifyTwice(TestImportToPackModifyTwice):
1461     branch_format = "1.9-rich-root"
1462
1463 class TestImportToRichRootModifyTricky(TestImportToPackModifyTricky):
1464     branch_format = "1.9-rich-root"
1465
1466 class TestImportToRichRootDelete(TestImportToPackDelete):
1467     branch_format = "1.9-rich-root"
1468
1469 class TestImportToRichRootDeleteNew(TestImportToPackDeleteNew):
1470     branch_format = "1.9-rich-root"
1471
1472 class TestImportToRichRootDeleteThenAdd(TestImportToPackDeleteThenAdd):
1473     branch_format = "1.9-rich-root"
1474
1475 class TestImportToRichRootDeleteDirectory(TestImportToPackDeleteDirectory):
1476     branch_format = "1.9-rich-root"
1477
1478 class TestImportToRichRootRename(TestImportToPackRename):
1479     branch_format = "1.9-rich-root"
1480
1481 class TestImportToRichRootRenameNew(TestImportToPackRenameNew):
1482     branch_format = "1.9-rich-root"
1483
1484 class TestImportToRichRootRenameToDeleted(TestImportToPackRenameToDeleted):
1485     branch_format = "1.9-rich-root"
1486
1487 class TestImportToRichRootRenameModified(TestImportToPackRenameModified):
1488     branch_format = "1.9-rich-root"
1489
1490 class TestImportToRichRootRenameTricky(TestImportToPackRenameTricky):
1491     branch_format = "1.9-rich-root"
1492
1493 class TestImportToRichRootCopy(TestImportToPackCopy):
1494     branch_format = "1.9-rich-root"
1495
1496 class TestImportToRichRootCopyNew(TestImportToPackCopyNew):
1497     branch_format = "1.9-rich-root"
1498
1499 class TestImportToRichRootCopyToDeleted(TestImportToPackCopyToDeleted):
1500     branch_format = "1.9-rich-root"
1501
1502 class TestImportToRichRootCopyModified(TestImportToPackCopyModified):
1503     branch_format = "1.9-rich-root"
1504
1505 class TestImportToRichRootFileKinds(TestImportToPackFileKinds):
1506     branch_format = "1.9-rich-root"
1507
1508 try:
1509     from bzrlib.repofmt.groupcompress_repo import RepositoryFormat2a
1510
1511     class TestImportToChkModify(TestImportToPackModify):
1512         branch_format = "2a"
1513
1514     class TestImportToChkModifyTwice(TestImportToPackModifyTwice):
1515         branch_format = "2a"
1516
1517     class TestImportToChkModifyTricky(TestImportToPackModifyTricky):
1518         branch_format = "2a"
1519
1520     class TestImportToChkDelete(TestImportToPackDelete):
1521         branch_format = "2a"
1522
1523     class TestImportToChkDeleteNew(TestImportToPackDeleteNew):
1524         branch_format = "2a"
1525
1526     class TestImportToChkDeleteThenAdd(TestImportToPackDeleteThenAdd):
1527         branch_format = "2a"
1528
1529     class TestImportToChkDeleteDirectory(TestImportToPackDeleteDirectory):
1530         branch_format = "2a"
1531
1532     class TestImportToChkRename(TestImportToPackRename):
1533         branch_format = "2a"
1534
1535     class TestImportToChkRenameNew(TestImportToPackRenameNew):
1536         branch_format = "2a"
1537
1538     class TestImportToChkRenameToDeleted(TestImportToPackRenameToDeleted):
1539         branch_format = "2a"
1540
1541     class TestImportToChkRenameModified(TestImportToPackRenameModified):
1542         branch_format = "2a"
1543
1544     class TestImportToChkRenameTricky(TestImportToPackRenameTricky):
1545         branch_format = "2a"
1546
1547     class TestImportToChkCopy(TestImportToPackCopy):
1548         branch_format = "2a"
1549
1550     class TestImportToChkCopyNew(TestImportToPackCopyNew):
1551         branch_format = "2a"
1552
1553     class TestImportToChkCopyToDeleted(TestImportToPackCopyToDeleted):
1554         branch_format = "2a"
1555
1556     class TestImportToChkCopyModified(TestImportToPackCopyModified):
1557         branch_format = "2a"
1558
1559     class TestImportToChkFileKinds(TestImportToPackFileKinds):
1560         branch_format = "2a"
1561
1562 except ImportError:
1563     pass