/breezy/unstable

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy/unstable

« back to all changes in this revision

Viewing changes to breezy/plugins/fastimport/tests/test_generic_processor.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-24 01:39:33 UTC
  • mfrom: (3815.3776.6)
  • Revision ID: jelmer@jelmer.uk-20170524013933-ir4y4tqtrsiz2ka2
New upstream snapshot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
from __future__ import absolute_import
 
17
 
 
18
import time
 
19
 
 
20
from .... import (
 
21
    tests,
 
22
    )
 
23
from ..helpers import (
 
24
    kind_to_mode,
 
25
    )
 
26
from . import (
 
27
    FastimportFeature,
 
28
    )
 
29
 
 
30
try:
 
31
    from fastimport import commands
 
32
except ImportError:
 
33
    commands = object()
 
34
 
 
35
 
 
36
def load_tests(standard_tests, module, loader):
 
37
    """Parameterize tests for all versions of groupcompress."""
 
38
    scenarios = [
 
39
        ('pack-0.92', {'branch_format': 'pack-0.92'}),
 
40
        ('1.9-rich-root', {'branch_format': '1.9-rich-root'}),
 
41
    ]
 
42
    try:
 
43
        from ....repofmt.groupcompress_repo import RepositoryFormat2a
 
44
        scenarios.append(('2a', {'branch_format': '2a'}))
 
45
    except ImportError:
 
46
        pass
 
47
    suite = loader.suiteClass()
 
48
    result = tests.multiply_tests(standard_tests, scenarios, suite)
 
49
    return result
 
50
 
 
51
 
 
52
class TestCaseForGenericProcessor(tests.TestCaseWithTransport):
 
53
 
 
54
    _test_needs_features = [FastimportFeature]
 
55
 
 
56
    branch_format = "pack-0.92"
 
57
 
 
58
    def get_handler(self):
 
59
        from ..processors import (
 
60
            generic_processor,
 
61
            )
 
62
        branch = self.make_branch('.', format=self.branch_format)
 
63
        handler = generic_processor.GenericProcessor(branch.bzrdir)
 
64
        return handler, branch
 
65
 
 
66
    # FIXME: [] as a default is bad, as it is mutable, but I want
 
67
    # to use None to mean "don't check this".
 
68
    def assertChanges(self, branch, revno, expected_added=[],
 
69
            expected_removed=[], expected_modified=[],
 
70
            expected_renamed=[], expected_kind_changed=[]):
 
71
        """Check the changes introduced in a revision of a branch.
 
72
 
 
73
        This method checks that a revision introduces expected changes.
 
74
        The required changes are passed in as a list, where
 
75
        each entry contains the needed information about the change.
 
76
 
 
77
        If you do not wish to assert anything about a particular
 
78
        category then pass None instead.
 
79
 
 
80
        branch: The branch.
 
81
        revno: revision number of revision to check.
 
82
        expected_added: a list of (filename,) tuples that must have
 
83
            been added in the delta.
 
84
        expected_removed: a list of (filename,) tuples that must have
 
85
            been removed in the delta.
 
86
        expected_modified: a list of (filename,) tuples that must have
 
87
            been modified in the delta.
 
88
        expected_renamed: a list of (old_path, new_path) tuples that
 
89
            must have been renamed in the delta.
 
90
        expected_kind_changed: a list of (path, old_kind, new_kind) tuples
 
91
            that must have been changed in the delta.
 
92
        :return: revtree1, revtree2
 
93
        """
 
94
        repo = branch.repository
 
95
        revtree1 = repo.revision_tree(branch.get_rev_id(revno - 1))
 
96
        revtree2 = repo.revision_tree(branch.get_rev_id(revno))
 
97
        changes = revtree2.changes_from(revtree1)
 
98
        self._check_changes(changes, expected_added, expected_removed,
 
99
            expected_modified, expected_renamed, expected_kind_changed)
 
100
        return revtree1, revtree2
 
101
 
 
102
    def _check_changes(self, changes, expected_added=[],
 
103
            expected_removed=[], expected_modified=[],
 
104
            expected_renamed=[], expected_kind_changed=[]):
 
105
        """Check the changes in a TreeDelta
 
106
 
 
107
        This method checks that the TreeDelta contains the expected
 
108
        modifications between the two trees that were used to generate
 
109
        it. The required changes are passed in as a list, where
 
110
        each entry contains the needed information about the change.
 
111
 
 
112
        If you do not wish to assert anything about a particular
 
113
        category then pass None instead.
 
114
 
 
115
        changes: The TreeDelta to check.
 
116
        expected_added: a list of (filename,) tuples that must have
 
117
            been added in the delta.
 
118
        expected_removed: a list of (filename,) tuples that must have
 
119
            been removed in the delta.
 
120
        expected_modified: a list of (filename,) tuples that must have
 
121
            been modified in the delta.
 
122
        expected_renamed: a list of (old_path, new_path) tuples that
 
123
            must have been renamed in the delta.
 
124
        expected_kind_changed: a list of (path, old_kind, new_kind) tuples
 
125
            that must have been changed in the delta.
 
126
        """
 
127
        renamed = changes.renamed
 
128
        added = changes.added
 
129
        removed = changes.removed
 
130
        modified = changes.modified
 
131
        kind_changed = changes.kind_changed
 
132
        if expected_renamed is not None:
 
133
            self.assertEquals(len(renamed), len(expected_renamed),
 
134
                "%s is renamed, expected %s" % (renamed, expected_renamed))
 
135
            renamed_files = [(item[0], item[1]) for item in renamed]
 
136
            for expected_renamed_entry in expected_renamed:
 
137
                self.assertTrue(expected_renamed_entry in renamed_files,
 
138
                    "%s is not renamed, %s are" % (str(expected_renamed_entry),
 
139
                        renamed_files))
 
140
        if expected_added is not None:
 
141
            self.assertEquals(len(added), len(expected_added),
 
142
                "%s is added" % str(added))
 
143
            added_files = [(item[0],) for item in added]
 
144
            for expected_added_entry in expected_added:
 
145
                self.assertTrue(expected_added_entry in added_files,
 
146
                    "%s is not added, %s are" % (str(expected_added_entry),
 
147
                        added_files))
 
148
        if expected_removed is not None:
 
149
            self.assertEquals(len(removed), len(expected_removed),
 
150
                "%s is removed" % str(removed))
 
151
            removed_files = [(item[0],) for item in removed]
 
152
            for expected_removed_entry in expected_removed:
 
153
                self.assertTrue(expected_removed_entry in removed_files,
 
154
                    "%s is not removed, %s are" % (str(expected_removed_entry),
 
155
                        removed_files))
 
156
        if expected_modified is not None:
 
157
            self.assertEquals(len(modified), len(expected_modified),
 
158
                "%s is modified" % str(modified))
 
159
            modified_files = [(item[0],) for item in modified]
 
160
            for expected_modified_entry in expected_modified:
 
161
                self.assertTrue(expected_modified_entry in modified_files,
 
162
                    "%s is not modified, %s are" % (
 
163
                    str(expected_modified_entry), modified_files))
 
164
        if expected_kind_changed is not None:
 
165
            self.assertEquals(len(kind_changed), len(expected_kind_changed),
 
166
                "%s is kind-changed, expected %s" % (kind_changed,
 
167
                    expected_kind_changed))
 
168
            kind_changed_files = [(item[0], item[2], item[3])
 
169
                for item in kind_changed]
 
170
            for expected_kind_changed_entry in expected_kind_changed:
 
171
                self.assertTrue(expected_kind_changed_entry in
 
172
                    kind_changed_files, "%s is not kind-changed, %s are" % (
 
173
                    str(expected_kind_changed_entry), kind_changed_files))
 
174
 
 
175
    def assertContent(self, branch, tree, path, content):
 
176
        file_id = tree.path2id(path)
 
177
        branch.lock_read()
 
178
        self.addCleanup(branch.unlock)
 
179
        self.assertEqual(tree.get_file_text(file_id), content)
 
180
 
 
181
    def assertSymlinkTarget(self, branch, tree, path, target):
 
182
        file_id = tree.path2id(path)
 
183
        branch.lock_read()
 
184
        self.addCleanup(branch.unlock)
 
185
        self.assertEqual(tree.get_symlink_target(file_id), target)
 
186
 
 
187
    def assertExecutable(self, branch, tree, path, executable):
 
188
        file_id = tree.path2id(path)
 
189
        branch.lock_read()
 
190
        self.addCleanup(branch.unlock)
 
191
        self.assertEqual(tree.is_executable(file_id), executable)
 
192
 
 
193
    def assertRevisionRoot(self, revtree, path):
 
194
        self.assertEqual(revtree.get_revision_id(),
 
195
                         revtree.get_file_revision(revtree.path2id(path)))
 
196
 
 
197
 
 
198
class TestImportToPackTag(TestCaseForGenericProcessor):
 
199
 
 
200
    def file_command_iter(self, path, kind='file', content='aaa',
 
201
        executable=False, to_kind=None, to_content='bbb', to_executable=None):
 
202
        # Revno 1: create a file or symlink
 
203
        # Revno 2: modify it
 
204
        if to_kind is None:
 
205
            to_kind = kind
 
206
        if to_executable is None:
 
207
            to_executable = executable
 
208
        def command_list():
 
209
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
210
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
211
            def files_one():
 
212
                yield commands.FileModifyCommand(path,
 
213
                    kind_to_mode(kind, executable), None, content)
 
214
            yield commands.CommitCommand('head', '1', author,
 
215
                committer, "commit 1", None, [], files_one)
 
216
            def files_two():
 
217
                yield commands.FileModifyCommand(path,
 
218
                    kind_to_mode(to_kind, to_executable), None, to_content)
 
219
 
 
220
            # pass "head" for from_ to show that #401249 is worse than I knew
 
221
            yield commands.CommitCommand('head', '2', author,
 
222
                committer, "commit 2", "head", [], files_two)
 
223
 
 
224
            yield commands.TagCommand('tag1', ':1', committer, "tag 1")
 
225
 
 
226
            # pass "head" for from_ to demonstrate #401249
 
227
            yield commands.TagCommand('tag2', 'head', committer, "tag 2")
 
228
        return command_list
 
229
 
 
230
    def test_tag(self):
 
231
        handler, branch = self.get_handler()
 
232
        path = 'a'
 
233
        raise tests.KnownFailure("non-mark committish not yet supported"
 
234
                                 "- bug #410249")
 
235
        handler.process(self.file_command_iter(path))
 
236
 
 
237
 
 
238
class TestImportToPackModify(TestCaseForGenericProcessor):
 
239
 
 
240
    def file_command_iter(self, path, kind='file', content='aaa',
 
241
        executable=False, to_kind=None, to_content='bbb', to_executable=None):
 
242
 
 
243
        # Revno 1: create a file or symlink
 
244
        # Revno 2: modify it
 
245
        if to_kind is None:
 
246
            to_kind = kind
 
247
        if to_executable is None:
 
248
            to_executable = executable
 
249
        mode = kind_to_mode(kind, executable)
 
250
        to_mode = kind_to_mode(to_kind, to_executable)
 
251
        def command_list():
 
252
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
253
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
254
            def files_one():
 
255
                yield commands.FileModifyCommand(path, mode, None, content)
 
256
            yield commands.CommitCommand('head', '1', author,
 
257
                committer, "commit 1", None, [], files_one)
 
258
            def files_two():
 
259
                yield commands.FileModifyCommand(path, to_mode, None, to_content)
 
260
            yield commands.CommitCommand('head', '2', author,
 
261
                committer, "commit 2", ":1", [], files_two)
 
262
        return command_list
 
263
 
 
264
    def test_modify_file_in_root(self):
 
265
        handler, branch = self.get_handler()
 
266
        path = 'a'
 
267
        handler.process(self.file_command_iter(path))
 
268
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
269
            expected_added=[(path,)])
 
270
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
271
            expected_modified=[(path,)])
 
272
        self.assertContent(branch, revtree1, path, "aaa")
 
273
        self.assertContent(branch, revtree2, path, "bbb")
 
274
        self.assertRevisionRoot(revtree1, path)
 
275
        self.assertRevisionRoot(revtree2, path)
 
276
 
 
277
    def test_modify_file_in_subdir(self):
 
278
        handler, branch = self.get_handler()
 
279
        path = 'a/a'
 
280
        handler.process(self.file_command_iter(path))
 
281
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
282
            expected_added=[('a',), (path,)])
 
283
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
284
            expected_modified=[(path,)])
 
285
        self.assertContent(branch, revtree1, path, "aaa")
 
286
        self.assertContent(branch, revtree2, path, "bbb")
 
287
 
 
288
    def test_modify_symlink_in_root(self):
 
289
        handler, branch = self.get_handler()
 
290
        path = 'a'
 
291
        handler.process(self.file_command_iter(path, kind='symlink'))
 
292
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
293
            expected_modified=[(path,)])
 
294
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
295
        self.assertSymlinkTarget(branch, revtree2, path, "bbb")
 
296
        self.assertRevisionRoot(revtree1, path)
 
297
        self.assertRevisionRoot(revtree2, path)
 
298
 
 
299
    def test_modify_symlink_in_subdir(self):
 
300
        handler, branch = self.get_handler()
 
301
        path = 'a/a'
 
302
        handler.process(self.file_command_iter(path, kind='symlink'))
 
303
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
304
            expected_added=[('a',), (path,)])
 
305
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
306
            expected_modified=[(path,)])
 
307
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
308
        self.assertSymlinkTarget(branch, revtree2, path, "bbb")
 
309
 
 
310
    def test_modify_file_becomes_symlink(self):
 
311
        handler, branch = self.get_handler()
 
312
        path = 'a/a'
 
313
        handler.process(self.file_command_iter(path,
 
314
            kind='file', to_kind='symlink'))
 
315
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
316
            expected_added=[('a',), (path,)])
 
317
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
318
            expected_kind_changed=[(path, 'file', 'symlink')])
 
319
        self.assertContent(branch, revtree1, path, "aaa")
 
320
        self.assertSymlinkTarget(branch, revtree2, path, "bbb")
 
321
 
 
322
    def test_modify_symlink_becomes_file(self):
 
323
        handler, branch = self.get_handler()
 
324
        path = 'a/a'
 
325
        handler.process(self.file_command_iter(path,
 
326
            kind='symlink', to_kind='file'))
 
327
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
328
            expected_added=[('a',), (path,)])
 
329
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
330
            expected_kind_changed=[(path, 'symlink', 'file')])
 
331
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
332
        self.assertContent(branch, revtree2, path, "bbb")
 
333
 
 
334
    def test_modify_file_now_executable(self):
 
335
        handler, branch = self.get_handler()
 
336
        path = 'a/a'
 
337
        handler.process(self.file_command_iter(path,
 
338
            executable=False, to_executable=True, to_content='aaa'))
 
339
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
340
            expected_added=[('a',), (path,)])
 
341
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
342
            expected_modified=[(path,)])
 
343
        self.assertExecutable(branch, revtree1, path, False)
 
344
        self.assertExecutable(branch, revtree2, path, True)
 
345
 
 
346
    def test_modify_file_no_longer_executable(self):
 
347
        handler, branch = self.get_handler()
 
348
        path = 'a/a'
 
349
        handler.process(self.file_command_iter(path,
 
350
            executable=True, to_executable=False, to_content='aaa'))
 
351
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
352
            expected_added=[('a',), (path,)])
 
353
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
354
            expected_modified=[(path,)])
 
355
        self.assertExecutable(branch, revtree1, path, True)
 
356
        self.assertExecutable(branch, revtree2, path, False)
 
357
 
 
358
 
 
359
class TestImportToPackModifyTwice(TestCaseForGenericProcessor):
 
360
    """This tests when the same file is modified twice in the one commit.
 
361
 
 
362
    Note: hg-fast-export produces data like this on occasions.
 
363
    """
 
364
 
 
365
    def file_command_iter(self, path, kind='file', content='aaa',
 
366
        executable=False, to_kind=None, to_content='bbb', to_executable=None):
 
367
 
 
368
        # Revno 1: create a file twice
 
369
        if to_kind is None:
 
370
            to_kind = kind
 
371
        if to_executable is None:
 
372
            to_executable = executable
 
373
        def command_list():
 
374
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
375
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
376
            def files_one():
 
377
                yield commands.FileModifyCommand(path, kind_to_mode(kind, executable),
 
378
                        None, content)
 
379
                yield commands.FileModifyCommand(path, kind_to_mode(to_kind, to_executable),
 
380
                        None, to_content)
 
381
            yield commands.CommitCommand('head', '1', author,
 
382
                committer, "commit 1", None, [], files_one)
 
383
        return command_list
 
384
 
 
385
    def test_modify_file_twice_in_root(self):
 
386
        handler, branch = self.get_handler()
 
387
        path = 'a'
 
388
        handler.process(self.file_command_iter(path))
 
389
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
390
            expected_added=[(path,)])
 
391
        self.assertContent(branch, revtree1, path, "aaa")
 
392
        self.assertRevisionRoot(revtree1, path)
 
393
 
 
394
 
 
395
class TestImportToPackModifyTricky(TestCaseForGenericProcessor):
 
396
 
 
397
    def file_command_iter(self, path1, path2, kind='file'):
 
398
 
 
399
        # Revno 1: create a file or symlink in a directory
 
400
        # Revno 2: create a second file that implicitly deletes the
 
401
        # first one because either:
 
402
        # * the new file is a in directory with the old file name
 
403
        # * the new file has the same name as the directory of the first
 
404
        def command_list():
 
405
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
406
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
407
            def files_one():
 
408
                yield commands.FileModifyCommand(path1, kind_to_mode(kind, False),
 
409
                        None, "aaa")
 
410
            yield commands.CommitCommand('head', '1', author,
 
411
                committer, "commit 1", None, [], files_one)
 
412
            def files_two():
 
413
                yield commands.FileModifyCommand(path2, kind_to_mode(kind, False),
 
414
                        None, "bbb")
 
415
            yield commands.CommitCommand('head', '2', author,
 
416
                committer, "commit 2", ":1", [], files_two)
 
417
        return command_list
 
418
 
 
419
 
 
420
    def test_modify_file_becomes_directory(self):
 
421
        handler, branch = self.get_handler()
 
422
        path1 = 'a/b'
 
423
        path2 = 'a/b/c'
 
424
        handler.process(self.file_command_iter(path1, path2))
 
425
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
426
            expected_added=[('a',), (path1,)])
 
427
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
428
            expected_added=[(path2,)],
 
429
            expected_kind_changed=[(path1, 'file', 'directory')])
 
430
        self.assertContent(branch, revtree1, path1, "aaa")
 
431
        self.assertContent(branch, revtree2, path2, "bbb")
 
432
 
 
433
    def test_modify_directory_becomes_file(self):
 
434
        handler, branch = self.get_handler()
 
435
        path1 = 'a/b/c'
 
436
        path2 = 'a/b'
 
437
        handler.process(self.file_command_iter(path1, path2))
 
438
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
439
            expected_added=[('a',), ('a/b',), (path1,)])
 
440
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
441
            expected_removed=[(path1,),],
 
442
            expected_kind_changed=[(path2, 'directory', 'file')])
 
443
        self.assertContent(branch, revtree1, path1, "aaa")
 
444
        self.assertContent(branch, revtree2, path2, "bbb")
 
445
 
 
446
    def test_modify_symlink_becomes_directory(self):
 
447
        handler, branch = self.get_handler()
 
448
        path1 = 'a/b'
 
449
        path2 = 'a/b/c'
 
450
        handler.process(self.file_command_iter(path1, path2, 'symlink'))
 
451
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
452
            expected_added=[('a',), (path1,)])
 
453
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
454
            expected_added=[(path2,)],
 
455
            expected_kind_changed=[(path1, 'symlink', 'directory')])
 
456
        self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
 
457
        self.assertSymlinkTarget(branch, revtree2, path2, "bbb")
 
458
 
 
459
    def test_modify_directory_becomes_symlink(self):
 
460
        handler, branch = self.get_handler()
 
461
        path1 = 'a/b/c'
 
462
        path2 = 'a/b'
 
463
        handler.process(self.file_command_iter(path1, path2, 'symlink'))
 
464
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
465
            expected_added=[('a',), ('a/b',), (path1,)])
 
466
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
467
            expected_removed=[(path1,),],
 
468
            expected_kind_changed=[(path2, 'directory', 'symlink')])
 
469
        self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
 
470
        self.assertSymlinkTarget(branch, revtree2, path2, "bbb")
 
471
 
 
472
 
 
473
class TestImportToPackDelete(TestCaseForGenericProcessor):
 
474
 
 
475
    def file_command_iter(self, path, kind='file'):
 
476
 
 
477
        # Revno 1: create a file or symlink
 
478
        # Revno 2: delete it
 
479
        def command_list():
 
480
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
481
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
482
            def files_one():
 
483
                yield commands.FileModifyCommand(path, kind_to_mode(kind, False),
 
484
                        None, "aaa")
 
485
            yield commands.CommitCommand('head', '1', author,
 
486
                committer, "commit 1", None, [], files_one)
 
487
            def files_two():
 
488
                yield commands.FileDeleteCommand(path)
 
489
            yield commands.CommitCommand('head', '2', author,
 
490
                committer, "commit 2", ":1", [], files_two)
 
491
        return command_list
 
492
 
 
493
    def test_delete_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
            expected_added=[(path,)])
 
499
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
500
            expected_removed=[(path,)])
 
501
        self.assertContent(branch, revtree1, path, "aaa")
 
502
        self.assertRevisionRoot(revtree1, path)
 
503
 
 
504
    def test_delete_file_in_subdir(self):
 
505
        handler, branch = self.get_handler()
 
506
        path = 'a/a'
 
507
        handler.process(self.file_command_iter(path))
 
508
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
509
            expected_added=[('a',), (path,)])
 
510
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
511
            expected_removed=[('a',), (path,)])
 
512
        self.assertContent(branch, revtree1, path, "aaa")
 
513
 
 
514
    def test_delete_symlink_in_root(self):
 
515
        handler, branch = self.get_handler()
 
516
        path = 'a'
 
517
        handler.process(self.file_command_iter(path, kind='symlink'))
 
518
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
519
            expected_removed=[(path,)])
 
520
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
521
        self.assertRevisionRoot(revtree1, path)
 
522
 
 
523
    def test_delete_symlink_in_subdir(self):
 
524
        handler, branch = self.get_handler()
 
525
        path = 'a/a'
 
526
        handler.process(self.file_command_iter(path, kind='symlink'))
 
527
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
528
            expected_added=[('a',), (path,)])
 
529
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
530
            expected_removed=[('a',), (path,)])
 
531
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
532
 
 
533
    def test_delete_file_in_deep_subdir(self):
 
534
        handler, branch = self.get_handler()
 
535
        path = 'a/b/c/d'
 
536
        handler.process(self.file_command_iter(path))
 
537
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
538
            expected_added=[('a',), ('a/b',), ('a/b/c',), (path,)])
 
539
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
540
            expected_removed=[('a',), ('a/b',), ('a/b/c',), (path,)])
 
541
        self.assertContent(branch, revtree1, path, "aaa")
 
542
 
 
543
 
 
544
class TestImportToPackDeleteNew(TestCaseForGenericProcessor):
 
545
    """Test deletion of a newly added file."""
 
546
 
 
547
    def file_command_iter(self, path, kind='file'):
 
548
 
 
549
        # Revno 1: create a file or symlink then delete it
 
550
        def command_list():
 
551
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
552
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
553
            def files_one():
 
554
                yield commands.FileModifyCommand(path, kind_to_mode(kind, False),
 
555
                        None, "aaa")
 
556
                yield commands.FileDeleteCommand(path)
 
557
            yield commands.CommitCommand('head', '1', author,
 
558
                committer, "commit 1", None, [], files_one)
 
559
        return command_list
 
560
 
 
561
    def test_delete_new_file_in_root(self):
 
562
        handler, branch = self.get_handler()
 
563
        path = 'a'
 
564
        handler.process(self.file_command_iter(path))
 
565
        revtree0, revtree1 = self.assertChanges(branch, 1,)
 
566
 
 
567
    def test_delete_new_file_in_subdir(self):
 
568
        handler, branch = self.get_handler()
 
569
        path = 'a/a'
 
570
        handler.process(self.file_command_iter(path))
 
571
        revtree0, revtree1 = self.assertChanges(branch, 1,)
 
572
 
 
573
    def test_delete_new_symlink_in_root(self):
 
574
        handler, branch = self.get_handler()
 
575
        path = 'a'
 
576
        handler.process(self.file_command_iter(path, kind='symlink'))
 
577
        revtree0, revtree1 = self.assertChanges(branch, 1,)
 
578
 
 
579
    def test_delete_new_symlink_in_subdir(self):
 
580
        handler, branch = self.get_handler()
 
581
        path = 'a/a'
 
582
        handler.process(self.file_command_iter(path, kind='symlink'))
 
583
        revtree0, revtree1 = self.assertChanges(branch, 1,)
 
584
 
 
585
    def test_delete_new_file_in_deep_subdir(self):
 
586
        handler, branch = self.get_handler()
 
587
        path = 'a/b/c/d'
 
588
        handler.process(self.file_command_iter(path))
 
589
        revtree0, revtree1 = self.assertChanges(branch, 1,)
 
590
 
 
591
 
 
592
class TestImportToPackDeleteMultiLevel(TestCaseForGenericProcessor):
 
593
 
 
594
    def file_command_iter(self, paths, paths_to_delete):
 
595
 
 
596
        # Revno 1: create multiple files
 
597
        # Revno 2: delete multiple files
 
598
        def command_list():
 
599
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
600
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
601
            def files_one():
 
602
                for i, path in enumerate(paths):
 
603
                    yield commands.FileModifyCommand(path, kind_to_mode('file', False),
 
604
                            None, "aaa%d" % i)
 
605
            yield commands.CommitCommand('head', '1', author,
 
606
                committer, "commit 1", None, [], files_one)
 
607
            def files_two():
 
608
                for path in paths_to_delete:
 
609
                    yield commands.FileDeleteCommand(path)
 
610
            yield commands.CommitCommand('head', '2', author,
 
611
                committer, "commit 2", ":1", [], files_two)
 
612
        return command_list
 
613
 
 
614
    def test_delete_files_in_multiple_levels(self):
 
615
        handler, branch = self.get_handler()
 
616
        paths = ['a/b/c', 'a/b/d/e']
 
617
        paths_to_delete = ['a/b/c', 'a/b/d/e']
 
618
        handler.process(self.file_command_iter(paths, paths_to_delete))
 
619
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
620
            expected_added=[
 
621
                ('a',), ('a/b',), ('a/b/c',),
 
622
                ('a/b/d',), ('a/b/d/e',),
 
623
                ])
 
624
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
625
            expected_removed=[
 
626
                ('a',), ('a/b',), ('a/b/c',),
 
627
                ('a/b/d',), ('a/b/d/e',),
 
628
                ])
 
629
 
 
630
    def test_delete_file_single_level(self):
 
631
        handler, branch = self.get_handler()
 
632
        paths = ['a/b/c', 'a/b/d/e']
 
633
        paths_to_delete = ['a/b/d/e']
 
634
        handler.process(self.file_command_iter(paths, paths_to_delete))
 
635
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
636
            expected_added=[
 
637
                ('a',), ('a/b',), ('a/b/c',),
 
638
                ('a/b/d',), ('a/b/d/e',),
 
639
                ])
 
640
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
641
            expected_removed=[
 
642
                ('a/b/d',), ('a/b/d/e',),
 
643
                ])
 
644
 
 
645
    def test_delete_file_complex_level(self):
 
646
        handler, branch = self.get_handler()
 
647
        paths = ['a/b/c', 'a/b/d/e', 'a/f/g', 'a/h', 'a/b/d/i/j']
 
648
        paths_to_delete = ['a/b/c', 'a/b/d/e', 'a/f/g', 'a/b/d/i/j']
 
649
        handler.process(self.file_command_iter(paths, paths_to_delete))
 
650
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
651
            expected_added=[
 
652
                ('a',), ('a/b',), ('a/b/c',),
 
653
                ('a/b/d',), ('a/b/d/e',),
 
654
                ('a/f',), ('a/f/g',),
 
655
                ('a/h',),
 
656
                ('a/b/d/i',), ('a/b/d/i/j',),
 
657
                ])
 
658
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
659
            expected_removed=[
 
660
                ('a/b',), ('a/b/c',),
 
661
                ('a/b/d',), ('a/b/d/e',),
 
662
                ('a/f',), ('a/f/g',),
 
663
                ('a/b/d/i',), ('a/b/d/i/j',),
 
664
                ])
 
665
 
 
666
class TestImportToPackDeleteThenAdd(TestCaseForGenericProcessor):
 
667
    """Test delete followed by an add. Merges can cause this."""
 
668
 
 
669
    def file_command_iter(self, path, kind='file', content='aaa',
 
670
        executable=False, to_kind=None, to_content='bbb', to_executable=None):
 
671
 
 
672
        # Revno 1: create a file or symlink
 
673
        # Revno 2: delete it and add it
 
674
        if to_kind is None:
 
675
            to_kind = kind
 
676
        if to_executable is None:
 
677
            to_executable = executable
 
678
        def command_list():
 
679
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
680
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
681
            def files_one():
 
682
                yield commands.FileModifyCommand(path, kind_to_mode(kind, executable),
 
683
                        None, content)
 
684
            yield commands.CommitCommand('head', '1', author,
 
685
                committer, "commit 1", None, [], files_one)
 
686
            def files_two():
 
687
                yield commands.FileDeleteCommand(path)
 
688
                yield commands.FileModifyCommand(path, kind_to_mode(to_kind, to_executable),
 
689
                        None, to_content)
 
690
            yield commands.CommitCommand('head', '2', author,
 
691
                committer, "commit 2", ":1", [], files_two)
 
692
        return command_list
 
693
 
 
694
    def test_delete_then_add_file_in_root(self):
 
695
        handler, branch = self.get_handler()
 
696
        path = 'a'
 
697
        handler.process(self.file_command_iter(path))
 
698
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
699
            expected_added=[(path,)])
 
700
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
701
            expected_removed=[(path,)],
 
702
            expected_added=[(path,)])
 
703
        self.assertContent(branch, revtree1, path, "aaa")
 
704
        self.assertContent(branch, revtree2, path, "bbb")
 
705
        self.assertRevisionRoot(revtree1, path)
 
706
        self.assertRevisionRoot(revtree2, path)
 
707
 
 
708
    def test_delete_then_add_file_in_subdir(self):
 
709
        handler, branch = self.get_handler()
 
710
        path = 'a/a'
 
711
        handler.process(self.file_command_iter(path))
 
712
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
713
            expected_added=[('a',), (path,)])
 
714
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
715
            expected_removed=[(path,)],
 
716
            expected_added=[(path,)])
 
717
        self.assertContent(branch, revtree1, path, "aaa")
 
718
        self.assertContent(branch, revtree2, path, "bbb")
 
719
 
 
720
    def test_delete_then_add_symlink_in_root(self):
 
721
        handler, branch = self.get_handler()
 
722
        path = 'a'
 
723
        handler.process(self.file_command_iter(path, kind='symlink'))
 
724
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
725
            expected_removed=[(path,)],
 
726
            expected_added=[(path,)])
 
727
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
728
        self.assertSymlinkTarget(branch, revtree2, path, "bbb")
 
729
        self.assertRevisionRoot(revtree1, path)
 
730
        self.assertRevisionRoot(revtree2, path)
 
731
 
 
732
    def test_delete_then_add_symlink_in_subdir(self):
 
733
        handler, branch = self.get_handler()
 
734
        path = 'a/a'
 
735
        handler.process(self.file_command_iter(path, kind='symlink'))
 
736
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
737
            expected_added=[('a',), (path,)])
 
738
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
739
            expected_removed=[(path,)],
 
740
            expected_added=[(path,)])
 
741
        self.assertSymlinkTarget(branch, revtree1, path, "aaa")
 
742
        self.assertSymlinkTarget(branch, revtree2, path, "bbb")
 
743
 
 
744
 
 
745
class TestImportToPackDeleteDirectory(TestCaseForGenericProcessor):
 
746
 
 
747
    def file_command_iter(self, paths, dir):
 
748
 
 
749
        # Revno 1: create multiple files
 
750
        # Revno 2: delete a directory holding those files
 
751
        def command_list():
 
752
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
753
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
754
            def files_one():
 
755
                for i, path in enumerate(paths):
 
756
                    yield commands.FileModifyCommand(path, kind_to_mode('file', False),
 
757
                            None, "aaa%d" % i)
 
758
            yield commands.CommitCommand('head', '1', author,
 
759
                committer, "commit 1", None, [], files_one)
 
760
            def files_two():
 
761
                yield commands.FileDeleteCommand(dir)
 
762
            yield commands.CommitCommand('head', '2', author,
 
763
                committer, "commit 2", ":1", [], files_two)
 
764
        return command_list
 
765
 
 
766
    def test_delete_dir(self):
 
767
        handler, branch = self.get_handler()
 
768
        paths = ['a/b/c', 'a/b/d', 'a/b/e/f', 'a/g']
 
769
        dir = 'a/b'
 
770
        handler.process(self.file_command_iter(paths, dir))
 
771
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
772
            expected_added=[
 
773
                ('a',), ('a/b',), ('a/b/c',),
 
774
                ('a/b/d',),
 
775
                ('a/b/e',), ('a/b/e/f',),
 
776
                ('a/g',),
 
777
                ])
 
778
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
779
            expected_removed=[
 
780
                ('a/b',), ('a/b/c',),
 
781
                ('a/b/d',),
 
782
                ('a/b/e',), ('a/b/e/f',),
 
783
                ])
 
784
 
 
785
 
 
786
class TestImportToPackDeleteDirectoryThenAddFile(TestCaseForGenericProcessor):
 
787
    """Test deleting a directory then adding a file in the same commit."""
 
788
 
 
789
    def file_command_iter(self, paths, dir, new_path, kind='file'):
 
790
 
 
791
        # Revno 1: create files in a directory
 
792
        # Revno 2: delete the directory then add a file into it
 
793
        def command_list():
 
794
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
795
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
796
            def files_one():
 
797
                for i, path in enumerate(paths):
 
798
                    yield commands.FileModifyCommand(path, kind_to_mode(kind, False),
 
799
                            None, "aaa%d" % i)
 
800
            yield commands.CommitCommand('head', '1', author,
 
801
                committer, "commit 1", None, [], files_one)
 
802
            def files_two():
 
803
                yield commands.FileDeleteCommand(dir)
 
804
                yield commands.FileModifyCommand(new_path, kind_to_mode(kind, False),
 
805
                        None, "bbb")
 
806
            yield commands.CommitCommand('head', '2', author,
 
807
                committer, "commit 2", ":1", [], files_two)
 
808
        return command_list
 
809
 
 
810
    def test_delete_dir_then_add_file(self):
 
811
        handler, branch = self.get_handler()
 
812
        paths = ['a/b/c', 'a/b/d']
 
813
        dir = 'a/b'
 
814
        new_path = 'a/b/z'
 
815
        handler.process(self.file_command_iter(paths, dir, new_path))
 
816
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
817
            expected_added=[('a',), ('a/b',), ('a/b/c',), ('a/b/d',),])
 
818
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
819
            expected_removed=[('a/b',), ('a/b/c',), ('a/b/d',)],
 
820
            expected_added=[('a/b',), ('a/b/z',)])
 
821
        self.assertContent(branch, revtree2, new_path, "bbb")
 
822
 
 
823
    def test_delete_dir_then_add_symlink(self):
 
824
        handler, branch = self.get_handler()
 
825
        paths = ['a/b/c', 'a/b/d']
 
826
        dir = 'a/b'
 
827
        new_path = 'a/b/z'
 
828
        handler.process(self.file_command_iter(paths, dir, new_path, 'symlink'))
 
829
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
830
            expected_added=[('a',), ('a/b',), ('a/b/c',), ('a/b/d',),])
 
831
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
832
            expected_removed=[('a/b',), ('a/b/c',), ('a/b/d',)],
 
833
            expected_added=[('a/b',), ('a/b/z',)])
 
834
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
835
 
 
836
 
 
837
class TestImportToPackRename(TestCaseForGenericProcessor):
 
838
 
 
839
    def get_command_iter(self, old_path, new_path, kind='file'):
 
840
 
 
841
        # Revno 1: create a file or symlink
 
842
        # Revno 2: rename it
 
843
        def command_list():
 
844
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
845
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
846
            def files_one():
 
847
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
848
                        None, "aaa")
 
849
            yield commands.CommitCommand('head', '1', author,
 
850
                committer, "commit 1", None, [], files_one)
 
851
            def files_two():
 
852
                yield commands.FileRenameCommand(old_path, new_path)
 
853
            yield commands.CommitCommand('head', '2', author,
 
854
                committer, "commit 2", ":1", [], files_two)
 
855
        return command_list
 
856
 
 
857
    def test_rename_file_in_root(self):
 
858
        handler, branch = self.get_handler()
 
859
        old_path = 'a'
 
860
        new_path = 'b'
 
861
        handler.process(self.get_command_iter(old_path, new_path))
 
862
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
863
            expected_renamed=[(old_path, new_path)])
 
864
        self.assertRevisionRoot(revtree1, old_path)
 
865
        self.assertRevisionRoot(revtree2, new_path)
 
866
 
 
867
    def test_rename_symlink_in_root(self):
 
868
        handler, branch = self.get_handler()
 
869
        old_path = 'a'
 
870
        new_path = 'b'
 
871
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
872
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
873
            expected_renamed=[(old_path, new_path)])
 
874
        self.assertRevisionRoot(revtree1, old_path)
 
875
        self.assertRevisionRoot(revtree2, new_path)
 
876
 
 
877
    def test_rename_file_in_subdir(self):
 
878
        handler, branch = self.get_handler()
 
879
        old_path = 'a/a'
 
880
        new_path = 'a/b'
 
881
        handler.process(self.get_command_iter(old_path, new_path))
 
882
        self.assertChanges(branch, 2, expected_renamed=[(old_path, new_path)])
 
883
 
 
884
    def test_rename_symlink_in_subdir(self):
 
885
        handler, branch = self.get_handler()
 
886
        old_path = 'a/a'
 
887
        new_path = 'a/b'
 
888
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
889
        self.assertChanges(branch, 2, expected_renamed=[(old_path, new_path)])
 
890
 
 
891
    def test_rename_file_to_new_dir(self):
 
892
        handler, branch = self.get_handler()
 
893
        old_path = 'a/a'
 
894
        new_path = 'b/a'
 
895
        handler.process(self.get_command_iter(old_path, new_path))
 
896
        self.assertChanges(branch, 2,
 
897
            expected_renamed=[(old_path, new_path)],
 
898
            expected_added=[('b',)],
 
899
            expected_removed=[('a',)])
 
900
 
 
901
    def test_rename_symlink_to_new_dir(self):
 
902
        handler, branch = self.get_handler()
 
903
        old_path = 'a/a'
 
904
        new_path = 'b/a'
 
905
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
906
        self.assertChanges(branch, 2,
 
907
            expected_renamed=[(old_path, new_path)],
 
908
            expected_added=[('b',)],
 
909
            expected_removed=[('a',)])
 
910
 
 
911
 
 
912
class TestImportToPackRenameNew(TestCaseForGenericProcessor):
 
913
    """Test rename of a newly added file."""
 
914
 
 
915
    def get_command_iter(self, old_path, new_path, kind='file'):
 
916
 
 
917
        # Revno 1: create a file and rename it
 
918
        def command_list():
 
919
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
920
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
921
            def files_one():
 
922
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
923
                        None, "aaa")
 
924
                yield commands.FileRenameCommand(old_path, new_path)
 
925
            yield commands.CommitCommand('head', '1', author,
 
926
                committer, "commit 1", None, [], files_one)
 
927
        return command_list
 
928
 
 
929
    def test_rename_new_file_in_root(self):
 
930
        handler, branch = self.get_handler()
 
931
        old_path = 'a'
 
932
        new_path = 'b'
 
933
        handler.process(self.get_command_iter(old_path, new_path))
 
934
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
935
            expected_added=[(new_path,)])
 
936
        self.assertRevisionRoot(revtree1, new_path)
 
937
 
 
938
    def test_rename_new_symlink_in_root(self):
 
939
        handler, branch = self.get_handler()
 
940
        old_path = 'a'
 
941
        new_path = 'b'
 
942
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
943
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
944
            expected_added=[(new_path,)])
 
945
        self.assertRevisionRoot(revtree1, new_path)
 
946
 
 
947
    def test_rename_new_file_in_subdir(self):
 
948
        handler, branch = self.get_handler()
 
949
        old_path = 'a/a'
 
950
        new_path = 'a/b'
 
951
        handler.process(self.get_command_iter(old_path, new_path))
 
952
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
953
            expected_added=[('a',), (new_path,)])
 
954
 
 
955
    def test_rename_new_symlink_in_subdir(self):
 
956
        handler, branch = self.get_handler()
 
957
        old_path = 'a/a'
 
958
        new_path = 'a/b'
 
959
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
960
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
961
            expected_added=[('a',), (new_path,)])
 
962
 
 
963
 
 
964
class TestImportToPackRenameToDeleted(TestCaseForGenericProcessor):
 
965
    """Test rename to a destination path deleted in this commit."""
 
966
 
 
967
    def get_command_iter(self, old_path, new_path, kind='file'):
 
968
 
 
969
        # Revno 1: create two files
 
970
        # Revno 2: delete one, rename the other one to that path
 
971
        def command_list():
 
972
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
973
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
974
            def files_one():
 
975
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
976
                        None, "aaa")
 
977
                yield commands.FileModifyCommand(new_path, kind_to_mode(kind, False),
 
978
                        None, "bbb")
 
979
            yield commands.CommitCommand('head', '1', author,
 
980
                committer, "commit 1", None, [], files_one)
 
981
            def files_two():
 
982
                yield commands.FileDeleteCommand(new_path)
 
983
                yield commands.FileRenameCommand(old_path, new_path)
 
984
            yield commands.CommitCommand('head', '2', author,
 
985
                committer, "commit 2", ":1", [], files_two)
 
986
        return command_list
 
987
 
 
988
    def test_rename_to_deleted_file_in_root(self):
 
989
        handler, branch = self.get_handler()
 
990
        old_path = 'a'
 
991
        new_path = 'b'
 
992
        handler.process(self.get_command_iter(old_path, new_path))
 
993
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
994
            expected_added=[(old_path,), (new_path,)])
 
995
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
996
            expected_removed=[(new_path,)],
 
997
            expected_renamed=[(old_path, new_path)])
 
998
        self.assertContent(branch, revtree1, old_path, "aaa")
 
999
        self.assertContent(branch, revtree1, new_path, "bbb")
 
1000
        self.assertContent(branch, revtree2, new_path, "aaa")
 
1001
        self.assertRevisionRoot(revtree1, old_path)
 
1002
        self.assertRevisionRoot(revtree1, new_path)
 
1003
 
 
1004
    def test_rename_to_deleted_symlink_in_root(self):
 
1005
        handler, branch = self.get_handler()
 
1006
        old_path = 'a'
 
1007
        new_path = 'b'
 
1008
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1009
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1010
            expected_added=[(old_path,), (new_path,)])
 
1011
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1012
            expected_removed=[(new_path,)],
 
1013
            expected_renamed=[(old_path, new_path)])
 
1014
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1015
        self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
 
1016
        self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
 
1017
        self.assertRevisionRoot(revtree1, old_path)
 
1018
        self.assertRevisionRoot(revtree1, new_path)
 
1019
 
 
1020
    def test_rename_to_deleted_file_in_subdir(self):
 
1021
        handler, branch = self.get_handler()
 
1022
        old_path = 'd/a'
 
1023
        new_path = 'd/b'
 
1024
        handler.process(self.get_command_iter(old_path, new_path))
 
1025
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1026
            expected_added=[('d',), (old_path,), (new_path,)])
 
1027
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1028
            expected_removed=[(new_path,)],
 
1029
            expected_renamed=[(old_path, new_path)])
 
1030
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1031
        self.assertContent(branch, revtree1, new_path, "bbb")
 
1032
        self.assertContent(branch, revtree2, new_path, "aaa")
 
1033
 
 
1034
    def test_rename_to_deleted_symlink_in_subdir(self):
 
1035
        handler, branch = self.get_handler()
 
1036
        old_path = 'd/a'
 
1037
        new_path = 'd/b'
 
1038
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1039
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1040
            expected_added=[('d',), (old_path,), (new_path,)])
 
1041
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1042
            expected_removed=[(new_path,)],
 
1043
            expected_renamed=[(old_path, new_path)])
 
1044
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1045
        self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
 
1046
        self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
 
1047
 
 
1048
    def test_rename_to_deleted_file_in_new_dir(self):
 
1049
        handler, branch = self.get_handler()
 
1050
        old_path = 'd1/a'
 
1051
        new_path = 'd2/b'
 
1052
        handler.process(self.get_command_iter(old_path, new_path))
 
1053
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1054
            expected_added=[('d1',), (old_path,), ('d2',), (new_path,)])
 
1055
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1056
            expected_removed=[('d1',), (new_path,)],
 
1057
            expected_renamed=[(old_path, new_path)])
 
1058
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1059
        self.assertContent(branch, revtree1, new_path, "bbb")
 
1060
        self.assertContent(branch, revtree2, new_path, "aaa")
 
1061
 
 
1062
    def test_rename_to_deleted_symlink_in_new_dir(self):
 
1063
        handler, branch = self.get_handler()
 
1064
        old_path = 'd1/a'
 
1065
        new_path = 'd2/b'
 
1066
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1067
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1068
            expected_added=[('d1',), (old_path,), ('d2',), (new_path,)])
 
1069
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1070
            expected_removed=[('d1',), (new_path,)],
 
1071
            expected_renamed=[(old_path, new_path)])
 
1072
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1073
        self.assertSymlinkTarget(branch, revtree1, new_path, "bbb")
 
1074
        self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
 
1075
 
 
1076
 
 
1077
class TestImportToPackRenameModified(TestCaseForGenericProcessor):
 
1078
    """Test rename of a path previously modified in this commit."""
 
1079
 
 
1080
    def get_command_iter(self, old_path, new_path, kind='file'):
 
1081
 
 
1082
        # Revno 1: create a file or symlink
 
1083
        # Revno 2: modify then rename it
 
1084
        def command_list():
 
1085
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1086
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1087
            def files_one():
 
1088
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
1089
                        None, "aaa")
 
1090
            yield commands.CommitCommand('head', '1', author,
 
1091
                committer, "commit 1", None, [], files_one)
 
1092
            def files_two():
 
1093
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
1094
                        None, "bbb")
 
1095
                yield commands.FileRenameCommand(old_path, new_path)
 
1096
            yield commands.CommitCommand('head', '2', author,
 
1097
                committer, "commit 2", ":1", [], files_two)
 
1098
        return command_list
 
1099
 
 
1100
    def test_rename_of_modified_file_in_root(self):
 
1101
        handler, branch = self.get_handler()
 
1102
        old_path = 'a'
 
1103
        new_path = 'b'
 
1104
        handler.process(self.get_command_iter(old_path, new_path))
 
1105
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1106
            expected_added=[(old_path,)])
 
1107
        # Note: the delta doesn't show the modification?
 
1108
        # The actual new content is validated in the assertions following.
 
1109
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1110
            expected_renamed=[(old_path, new_path)])
 
1111
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1112
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1113
        self.assertRevisionRoot(revtree1, old_path)
 
1114
        self.assertRevisionRoot(revtree2, new_path)
 
1115
 
 
1116
    def test_rename_of_modified_symlink_in_root(self):
 
1117
        handler, branch = self.get_handler()
 
1118
        old_path = 'a'
 
1119
        new_path = 'b'
 
1120
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1121
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1122
            expected_added=[(old_path,)])
 
1123
        # Note: the delta doesn't show the modification?
 
1124
        # The actual new content is validated in the assertions following.
 
1125
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1126
            expected_renamed=[(old_path, new_path)])
 
1127
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1128
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1129
        self.assertRevisionRoot(revtree1, old_path)
 
1130
        self.assertRevisionRoot(revtree2, new_path)
 
1131
 
 
1132
    def test_rename_of_modified_file_in_subdir(self):
 
1133
        handler, branch = self.get_handler()
 
1134
        old_path = 'd/a'
 
1135
        new_path = 'd/b'
 
1136
        handler.process(self.get_command_iter(old_path, new_path))
 
1137
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1138
            expected_added=[('d',), (old_path,)])
 
1139
        # Note: the delta doesn't show the modification?
 
1140
        # The actual new content is validated in the assertions following.
 
1141
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1142
            expected_renamed=[(old_path, new_path)])
 
1143
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1144
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1145
 
 
1146
    def test_rename_of_modified_symlink_in_subdir(self):
 
1147
        handler, branch = self.get_handler()
 
1148
        old_path = 'd/a'
 
1149
        new_path = 'd/b'
 
1150
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1151
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1152
            expected_added=[('d',), (old_path,)])
 
1153
        # Note: the delta doesn't show the modification?
 
1154
        # The actual new content is validated in the assertions following.
 
1155
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1156
            expected_renamed=[(old_path, new_path)])
 
1157
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1158
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1159
 
 
1160
    def test_rename_of_modified_file_to_new_dir(self):
 
1161
        handler, branch = self.get_handler()
 
1162
        old_path = 'd1/a'
 
1163
        new_path = 'd2/b'
 
1164
        handler.process(self.get_command_iter(old_path, new_path))
 
1165
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1166
            expected_added=[('d1',), (old_path,)])
 
1167
        # Note: the delta doesn't show the modification?
 
1168
        # The actual new content is validated in the assertions following.
 
1169
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1170
            expected_renamed=[(old_path, new_path)],
 
1171
            expected_added=[('d2',)],
 
1172
            expected_removed=[('d1',)])
 
1173
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1174
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1175
 
 
1176
    def test_rename_of_modified_symlink_to_new_dir(self):
 
1177
        handler, branch = self.get_handler()
 
1178
        old_path = 'd1/a'
 
1179
        new_path = 'd2/b'
 
1180
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1181
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1182
            expected_added=[('d1',), (old_path,)])
 
1183
        # Note: the delta doesn't show the modification?
 
1184
        # The actual new content is validated in the assertions following.
 
1185
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1186
            expected_renamed=[(old_path, new_path)],
 
1187
            expected_added=[('d2',)],
 
1188
            expected_removed=[('d1',)])
 
1189
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1190
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1191
 
 
1192
 
 
1193
class TestImportToPackRenameThenModify(TestCaseForGenericProcessor):
 
1194
    """Test rename of a path then modfy the new-path in the same commit."""
 
1195
 
 
1196
    def get_command_iter(self, old_path, new_path, kind='file'):
 
1197
 
 
1198
        # Revno 1: create a file or symlink
 
1199
        # Revno 2: rename it then modify the newly created path
 
1200
        def command_list():
 
1201
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1202
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1203
            def files_one():
 
1204
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
1205
                        None, "aaa")
 
1206
            yield commands.CommitCommand('head', '1', author,
 
1207
                committer, "commit 1", None, [], files_one)
 
1208
            def files_two():
 
1209
                yield commands.FileRenameCommand(old_path, new_path)
 
1210
                yield commands.FileModifyCommand(new_path, kind_to_mode(kind, False),
 
1211
                        None, "bbb")
 
1212
            yield commands.CommitCommand('head', '2', author,
 
1213
                committer, "commit 2", ":1", [], files_two)
 
1214
        return command_list
 
1215
 
 
1216
    def test_rename_then_modify_file_in_root(self):
 
1217
        handler, branch = self.get_handler()
 
1218
        old_path = 'a'
 
1219
        new_path = 'b'
 
1220
        handler.process(self.get_command_iter(old_path, new_path))
 
1221
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1222
            expected_added=[(old_path,)])
 
1223
        # Note: the delta doesn't show the modification?
 
1224
        # The actual new content is validated in the assertions following.
 
1225
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1226
            expected_renamed=[(old_path, new_path)])
 
1227
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1228
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1229
        self.assertRevisionRoot(revtree1, old_path)
 
1230
        self.assertRevisionRoot(revtree2, new_path)
 
1231
 
 
1232
    def test_rename_then_modify_file_in_subdir(self):
 
1233
        handler, branch = self.get_handler()
 
1234
        old_path = 'd/a'
 
1235
        new_path = 'd/b'
 
1236
        handler.process(self.get_command_iter(old_path, new_path))
 
1237
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1238
            expected_added=[('d',), (old_path,)])
 
1239
        # Note: the delta doesn't show the modification?
 
1240
        # The actual new content is validated in the assertions following.
 
1241
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1242
            expected_renamed=[(old_path, new_path)])
 
1243
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1244
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1245
 
 
1246
    def test_rename_then_modify_file_in_new_dir(self):
 
1247
        handler, branch = self.get_handler()
 
1248
        old_path = 'd1/a'
 
1249
        new_path = 'd2/b'
 
1250
        handler.process(self.get_command_iter(old_path, new_path))
 
1251
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1252
            expected_added=[('d1',), (old_path,)])
 
1253
        # Note: the delta doesn't show the modification?
 
1254
        # The actual new content is validated in the assertions following.
 
1255
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1256
            expected_renamed=[(old_path, new_path)],
 
1257
            expected_added=[('d2',)],
 
1258
            expected_removed=[('d1',)])
 
1259
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1260
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1261
 
 
1262
    def test_rename_then_modify_symlink_in_root(self):
 
1263
        handler, branch = self.get_handler()
 
1264
        old_path = 'a'
 
1265
        new_path = 'b'
 
1266
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1267
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1268
            expected_added=[(old_path,)])
 
1269
        # Note: the delta doesn't show the modification?
 
1270
        # The actual new content is validated in the assertions following.
 
1271
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1272
            expected_renamed=[(old_path, new_path)])
 
1273
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1274
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1275
        self.assertRevisionRoot(revtree1, old_path)
 
1276
        self.assertRevisionRoot(revtree2, new_path)
 
1277
 
 
1278
    def test_rename_then_modify_symlink_in_subdir(self):
 
1279
        handler, branch = self.get_handler()
 
1280
        old_path = 'd/a'
 
1281
        new_path = 'd/b'
 
1282
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1283
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1284
            expected_added=[('d',), (old_path,)])
 
1285
        # Note: the delta doesn't show the modification?
 
1286
        # The actual new content is validated in the assertions following.
 
1287
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1288
            expected_renamed=[(old_path, new_path)])
 
1289
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1290
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1291
 
 
1292
    def test_rename_then_modify_symlink_in_new_dir(self):
 
1293
        handler, branch = self.get_handler()
 
1294
        old_path = 'd1/a'
 
1295
        new_path = 'd2/b'
 
1296
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1297
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1298
            expected_added=[('d1',), (old_path,)])
 
1299
        # Note: the delta doesn't show the modification?
 
1300
        # The actual new content is validated in the assertions following.
 
1301
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1302
            expected_renamed=[(old_path, new_path)],
 
1303
            expected_added=[('d2',)],
 
1304
            expected_removed=[('d1',)])
 
1305
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1306
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1307
 
 
1308
 
 
1309
class TestImportToPackDeleteRenameThenModify(TestCaseForGenericProcessor):
 
1310
    """Test rename of to a deleted path then modfy the new-path in the same commit."""
 
1311
 
 
1312
    def get_command_iter(self, old_path, new_path, kind='file'):
 
1313
 
 
1314
        # Revno 1: create two files or symlinks
 
1315
        # Revno 2: delete one, rename the other to it then modify the newly created path
 
1316
        def command_list():
 
1317
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1318
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1319
            def files_one():
 
1320
                yield commands.FileModifyCommand(old_path, kind_to_mode(kind, False),
 
1321
                        None, "aaa")
 
1322
                yield commands.FileModifyCommand(new_path, kind_to_mode(kind, False),
 
1323
                        None, "zzz")
 
1324
            yield commands.CommitCommand('head', '1', author,
 
1325
                committer, "commit 1", None, [], files_one)
 
1326
            def files_two():
 
1327
                yield commands.FileDeleteCommand(new_path)
 
1328
                yield commands.FileRenameCommand(old_path, new_path)
 
1329
                yield commands.FileModifyCommand(new_path, kind_to_mode(kind, False),
 
1330
                        None, "bbb")
 
1331
            yield commands.CommitCommand('head', '2', author,
 
1332
                committer, "commit 2", ":1", [], files_two)
 
1333
        return command_list
 
1334
 
 
1335
    def test_delete_rename_then_modify_file_in_root(self):
 
1336
        handler, branch = self.get_handler()
 
1337
        old_path = 'a'
 
1338
        new_path = 'b'
 
1339
        handler.process(self.get_command_iter(old_path, new_path))
 
1340
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1341
            expected_added=[(old_path,), (new_path,)])
 
1342
        # Note: the delta doesn't show the modification?
 
1343
        # The actual new content is validated in the assertions following.
 
1344
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1345
            expected_removed=[(new_path,)],
 
1346
            expected_renamed=[(old_path, new_path)])
 
1347
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1348
        self.assertContent(branch, revtree1, new_path, "zzz")
 
1349
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1350
        self.assertRevisionRoot(revtree1, old_path)
 
1351
        self.assertRevisionRoot(revtree1, new_path)
 
1352
        self.assertRevisionRoot(revtree2, new_path)
 
1353
 
 
1354
    def test_delete_rename_then_modify_file_in_subdir(self):
 
1355
        handler, branch = self.get_handler()
 
1356
        old_path = 'd/a'
 
1357
        new_path = 'd/b'
 
1358
        handler.process(self.get_command_iter(old_path, new_path))
 
1359
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1360
            expected_added=[('d',), (old_path,), (new_path,)])
 
1361
        # Note: the delta doesn't show the modification?
 
1362
        # The actual new content is validated in the assertions following.
 
1363
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1364
            expected_removed=[(new_path,)],
 
1365
            expected_renamed=[(old_path, new_path)])
 
1366
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1367
        self.assertContent(branch, revtree1, new_path, "zzz")
 
1368
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1369
 
 
1370
    def test_delete_rename_then_modify_file_in_new_dir(self):
 
1371
        handler, branch = self.get_handler()
 
1372
        old_path = 'd1/a'
 
1373
        new_path = 'd2/b'
 
1374
        handler.process(self.get_command_iter(old_path, new_path))
 
1375
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1376
            expected_added=[('d1',), ('d2',), (old_path,), (new_path,)])
 
1377
        # Note: the delta doesn't show the modification?
 
1378
        # The actual new content is validated in the assertions following.
 
1379
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1380
            expected_removed=[('d1',), (new_path,)],
 
1381
            expected_renamed=[(old_path, new_path)])
 
1382
        self.assertContent(branch, revtree1, old_path, "aaa")
 
1383
        self.assertContent(branch, revtree1, new_path, "zzz")
 
1384
        self.assertContent(branch, revtree2, new_path, "bbb")
 
1385
 
 
1386
    def test_delete_rename_then_modify_symlink_in_root(self):
 
1387
        handler, branch = self.get_handler()
 
1388
        old_path = 'a'
 
1389
        new_path = 'b'
 
1390
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1391
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1392
            expected_added=[(old_path,), (new_path,)])
 
1393
        # Note: the delta doesn't show the modification?
 
1394
        # The actual new content is validated in the assertions following.
 
1395
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1396
            expected_removed=[(new_path,)],
 
1397
            expected_renamed=[(old_path, new_path)])
 
1398
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1399
        self.assertSymlinkTarget(branch, revtree1, new_path, "zzz")
 
1400
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1401
        self.assertRevisionRoot(revtree1, old_path)
 
1402
        self.assertRevisionRoot(revtree1, new_path)
 
1403
        self.assertRevisionRoot(revtree2, new_path)
 
1404
 
 
1405
    def test_delete_rename_then_modify_symlink_in_subdir(self):
 
1406
        handler, branch = self.get_handler()
 
1407
        old_path = 'd/a'
 
1408
        new_path = 'd/b'
 
1409
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1410
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1411
            expected_added=[('d',), (old_path,), (new_path,)])
 
1412
        # Note: the delta doesn't show the modification?
 
1413
        # The actual new content is validated in the assertions following.
 
1414
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1415
            expected_removed=[(new_path,)],
 
1416
            expected_renamed=[(old_path, new_path)])
 
1417
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1418
        self.assertSymlinkTarget(branch, revtree1, new_path, "zzz")
 
1419
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1420
 
 
1421
    def test_delete_rename_then_modify_symlink_in_new_dir(self):
 
1422
        handler, branch = self.get_handler()
 
1423
        old_path = 'd1/a'
 
1424
        new_path = 'd2/b'
 
1425
        handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
 
1426
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1427
            expected_added=[('d1',), ('d2',), (old_path,), (new_path,)])
 
1428
        # Note: the delta doesn't show the modification?
 
1429
        # The actual new content is validated in the assertions following.
 
1430
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1431
            expected_removed=[('d1',), (new_path,)],
 
1432
            expected_renamed=[(old_path, new_path)])
 
1433
        self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
 
1434
        self.assertSymlinkTarget(branch, revtree1, new_path, "zzz")
 
1435
        self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
 
1436
 
 
1437
 
 
1438
class TestImportToPackRenameTricky(TestCaseForGenericProcessor):
 
1439
 
 
1440
    def file_command_iter(self, path1, old_path2, new_path2, kind='file'):
 
1441
 
 
1442
        # Revno 1: create two files or symlinks in a directory
 
1443
        # Revno 2: rename the second file so that it implicitly deletes the
 
1444
        # first one because either:
 
1445
        # * the new file is a in directory with the old file name
 
1446
        # * the new file has the same name as the directory of the first
 
1447
        def command_list():
 
1448
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1449
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1450
            def files_one():
 
1451
                yield commands.FileModifyCommand(path1, kind_to_mode(kind, False),
 
1452
                        None, "aaa")
 
1453
                yield commands.FileModifyCommand(old_path2, kind_to_mode(kind, False),
 
1454
                        None, "bbb")
 
1455
            yield commands.CommitCommand('head', '1', author,
 
1456
                committer, "commit 1", None, [], files_one)
 
1457
            def files_two():
 
1458
                yield commands.FileRenameCommand(old_path2, new_path2)
 
1459
            yield commands.CommitCommand('head', '2', author,
 
1460
                committer, "commit 2", ":1", [], files_two)
 
1461
        return command_list
 
1462
 
 
1463
    def test_rename_file_becomes_directory(self):
 
1464
        handler, branch = self.get_handler()
 
1465
        old_path2 = 'foo'
 
1466
        path1     = 'a/b'
 
1467
        new_path2 = 'a/b/c'
 
1468
        handler.process(self.file_command_iter(path1, old_path2, new_path2))
 
1469
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1470
            expected_added=[('a',), (path1,), (old_path2,)])
 
1471
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1472
            expected_renamed=[(old_path2, new_path2)],
 
1473
            expected_kind_changed=[(path1, 'file', 'directory')])
 
1474
        self.assertContent(branch, revtree1, path1, "aaa")
 
1475
        self.assertContent(branch, revtree2, new_path2, "bbb")
 
1476
 
 
1477
    def test_rename_directory_becomes_file(self):
 
1478
        handler, branch = self.get_handler()
 
1479
        old_path2 = 'foo'
 
1480
        path1     = 'a/b/c'
 
1481
        new_path2 = 'a/b'
 
1482
        handler.process(self.file_command_iter(path1, old_path2, new_path2))
 
1483
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1484
            expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
 
1485
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1486
            expected_renamed=[(old_path2, new_path2)],
 
1487
            expected_removed=[(path1,), (new_path2,)])
 
1488
        self.assertContent(branch, revtree1, path1, "aaa")
 
1489
        self.assertContent(branch, revtree2, new_path2, "bbb")
 
1490
 
 
1491
    def test_rename_symlink_becomes_directory(self):
 
1492
        handler, branch = self.get_handler()
 
1493
        old_path2 = 'foo'
 
1494
        path1     = 'a/b'
 
1495
        new_path2 = 'a/b/c'
 
1496
        handler.process(self.file_command_iter(path1, old_path2, new_path2,
 
1497
            'symlink'))
 
1498
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1499
            expected_added=[('a',), (path1,), (old_path2,)])
 
1500
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1501
            expected_renamed=[(old_path2, new_path2)],
 
1502
            expected_kind_changed=[(path1, 'symlink', 'directory')])
 
1503
        self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
 
1504
        self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
 
1505
 
 
1506
    def test_rename_directory_becomes_symlink(self):
 
1507
        handler, branch = self.get_handler()
 
1508
        old_path2 = 'foo'
 
1509
        path1     = 'a/b/c'
 
1510
        new_path2 = 'a/b'
 
1511
        handler.process(self.file_command_iter(path1, old_path2, new_path2,
 
1512
            'symlink'))
 
1513
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1514
            expected_added=[('a',), ('a/b',), (path1,), (old_path2,)])
 
1515
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1516
            expected_renamed=[(old_path2, new_path2)],
 
1517
            expected_removed=[(path1,), (new_path2,)])
 
1518
        self.assertSymlinkTarget(branch, revtree1, path1, "aaa")
 
1519
        self.assertSymlinkTarget(branch, revtree2, new_path2, "bbb")
 
1520
 
 
1521
 
 
1522
class TestImportToPackCopy(TestCaseForGenericProcessor):
 
1523
 
 
1524
    def file_command_iter(self, src_path, dest_path, kind='file'):
 
1525
 
 
1526
        # Revno 1: create a file or symlink
 
1527
        # Revno 2: copy it
 
1528
        def command_list():
 
1529
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1530
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1531
            def files_one():
 
1532
                yield commands.FileModifyCommand(src_path, kind_to_mode(kind, False),
 
1533
                        None, "aaa")
 
1534
            yield commands.CommitCommand('head', '1', author,
 
1535
                committer, "commit 1", None, [], files_one)
 
1536
            def files_two():
 
1537
                yield commands.FileCopyCommand(src_path, dest_path)
 
1538
            yield commands.CommitCommand('head', '2', author,
 
1539
                committer, "commit 2", ":1", [], files_two)
 
1540
        return command_list
 
1541
 
 
1542
    def test_copy_file_in_root(self):
 
1543
        handler, branch = self.get_handler()
 
1544
        src_path = 'a'
 
1545
        dest_path = 'b'
 
1546
        handler.process(self.file_command_iter(src_path, dest_path))
 
1547
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1548
            expected_added=[(dest_path,)])
 
1549
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1550
        self.assertContent(branch, revtree2, src_path, "aaa")
 
1551
        self.assertContent(branch, revtree2, dest_path, "aaa")
 
1552
        self.assertRevisionRoot(revtree1, src_path)
 
1553
        self.assertRevisionRoot(revtree2, dest_path)
 
1554
 
 
1555
    def test_copy_file_in_subdir(self):
 
1556
        handler, branch = self.get_handler()
 
1557
        src_path = 'a/a'
 
1558
        dest_path = 'a/b'
 
1559
        handler.process(self.file_command_iter(src_path, dest_path))
 
1560
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1561
            expected_added=[(dest_path,)])
 
1562
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1563
        self.assertContent(branch, revtree2, src_path, "aaa")
 
1564
        self.assertContent(branch, revtree2, dest_path, "aaa")
 
1565
 
 
1566
    def test_copy_file_to_new_dir(self):
 
1567
        handler, branch = self.get_handler()
 
1568
        src_path = 'a/a'
 
1569
        dest_path = 'b/a'
 
1570
        handler.process(self.file_command_iter(src_path, dest_path))
 
1571
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1572
            expected_added=[('b',), (dest_path,)])
 
1573
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1574
        self.assertContent(branch, revtree2, src_path, "aaa")
 
1575
        self.assertContent(branch, revtree2, dest_path, "aaa")
 
1576
 
 
1577
    def test_copy_symlink_in_root(self):
 
1578
        handler, branch = self.get_handler()
 
1579
        src_path = 'a'
 
1580
        dest_path = 'b'
 
1581
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1582
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1583
            expected_added=[(dest_path,)])
 
1584
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1585
        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
 
1586
        self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
 
1587
        self.assertRevisionRoot(revtree1, src_path)
 
1588
        self.assertRevisionRoot(revtree2, dest_path)
 
1589
 
 
1590
    def test_copy_symlink_in_subdir(self):
 
1591
        handler, branch = self.get_handler()
 
1592
        src_path = 'a/a'
 
1593
        dest_path = 'a/b'
 
1594
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1595
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1596
            expected_added=[(dest_path,)])
 
1597
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1598
        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
 
1599
        self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
 
1600
 
 
1601
    def test_copy_symlink_to_new_dir(self):
 
1602
        handler, branch = self.get_handler()
 
1603
        src_path = 'a/a'
 
1604
        dest_path = 'b/a'
 
1605
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1606
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1607
            expected_added=[('b',), (dest_path,)])
 
1608
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1609
        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
 
1610
        self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
 
1611
 
 
1612
 
 
1613
class TestImportToPackCopyNew(TestCaseForGenericProcessor):
 
1614
    """Test copy of a newly added file."""
 
1615
 
 
1616
    def file_command_iter(self, src_path, dest_path, kind='file'):
 
1617
 
 
1618
        # Revno 1: create a file or symlink and copy it
 
1619
        def command_list():
 
1620
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1621
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1622
            def files_one():
 
1623
                yield commands.FileModifyCommand(src_path, kind_to_mode(kind, False),
 
1624
                        None, "aaa")
 
1625
                yield commands.FileCopyCommand(src_path, dest_path)
 
1626
            yield commands.CommitCommand('head', '1', author,
 
1627
                committer, "commit 1", None, [], files_one)
 
1628
        return command_list
 
1629
 
 
1630
    def test_copy_new_file_in_root(self):
 
1631
        handler, branch = self.get_handler()
 
1632
        src_path = 'a'
 
1633
        dest_path = 'b'
 
1634
        handler.process(self.file_command_iter(src_path, dest_path))
 
1635
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1636
            expected_added=[(src_path,), (dest_path,)])
 
1637
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1638
        self.assertContent(branch, revtree1, dest_path, "aaa")
 
1639
        self.assertRevisionRoot(revtree1, src_path)
 
1640
        self.assertRevisionRoot(revtree1, dest_path)
 
1641
 
 
1642
    def test_copy_new_file_in_subdir(self):
 
1643
        handler, branch = self.get_handler()
 
1644
        src_path = 'a/a'
 
1645
        dest_path = 'a/b'
 
1646
        handler.process(self.file_command_iter(src_path, dest_path))
 
1647
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1648
            expected_added=[('a',), (src_path,), (dest_path,)])
 
1649
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1650
        self.assertContent(branch, revtree1, dest_path, "aaa")
 
1651
 
 
1652
    def test_copy_new_file_to_new_dir(self):
 
1653
        handler, branch = self.get_handler()
 
1654
        src_path = 'a/a'
 
1655
        dest_path = 'b/a'
 
1656
        handler.process(self.file_command_iter(src_path, dest_path))
 
1657
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1658
            expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
 
1659
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1660
        self.assertContent(branch, revtree1, dest_path, "aaa")
 
1661
 
 
1662
    def test_copy_new_symlink_in_root(self):
 
1663
        handler, branch = self.get_handler()
 
1664
        src_path = 'a'
 
1665
        dest_path = 'b'
 
1666
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1667
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1668
            expected_added=[(src_path,), (dest_path,)])
 
1669
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1670
        self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
 
1671
        self.assertRevisionRoot(revtree1, src_path)
 
1672
        self.assertRevisionRoot(revtree1, dest_path)
 
1673
 
 
1674
    def test_copy_new_symlink_in_subdir(self):
 
1675
        handler, branch = self.get_handler()
 
1676
        src_path = 'a/a'
 
1677
        dest_path = 'a/b'
 
1678
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1679
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1680
            expected_added=[('a',), (src_path,), (dest_path,)])
 
1681
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1682
        self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
 
1683
 
 
1684
    def test_copy_new_symlink_to_new_dir(self):
 
1685
        handler, branch = self.get_handler()
 
1686
        src_path = 'a/a'
 
1687
        dest_path = 'b/a'
 
1688
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1689
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1690
            expected_added=[('a',), (src_path,), ('b',), (dest_path,)])
 
1691
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1692
        self.assertSymlinkTarget(branch, revtree1, dest_path, "aaa")
 
1693
 
 
1694
 
 
1695
class TestImportToPackCopyToDeleted(TestCaseForGenericProcessor):
 
1696
 
 
1697
    def file_command_iter(self, src_path, dest_path, kind='file'):
 
1698
 
 
1699
        # Revno 1: create two files or symlinks
 
1700
        # Revno 2: delete one and copy the other one to its path
 
1701
        def command_list():
 
1702
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1703
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1704
            def files_one():
 
1705
                yield commands.FileModifyCommand(src_path, kind_to_mode(kind, False),
 
1706
                        None, "aaa")
 
1707
                yield commands.FileModifyCommand(dest_path, kind_to_mode(kind, False),
 
1708
                        None, "bbb")
 
1709
            yield commands.CommitCommand('head', '1', author,
 
1710
                committer, "commit 1", None, [], files_one)
 
1711
            def files_two():
 
1712
                yield commands.FileDeleteCommand(dest_path)
 
1713
                yield commands.FileCopyCommand(src_path, dest_path)
 
1714
            yield commands.CommitCommand('head', '2', author,
 
1715
                committer, "commit 2", ":1", [], files_two)
 
1716
        return command_list
 
1717
 
 
1718
    def test_copy_to_deleted_file_in_root(self):
 
1719
        handler, branch = self.get_handler()
 
1720
        src_path = 'a'
 
1721
        dest_path = 'b'
 
1722
        handler.process(self.file_command_iter(src_path, dest_path))
 
1723
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1724
            expected_added=[(src_path,), (dest_path,)])
 
1725
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1726
            expected_removed=[(dest_path,)],
 
1727
            expected_added=[(dest_path,)])
 
1728
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1729
        self.assertContent(branch, revtree1, dest_path, "bbb")
 
1730
        self.assertContent(branch, revtree2, src_path, "aaa")
 
1731
        self.assertContent(branch, revtree2, dest_path, "aaa")
 
1732
        self.assertRevisionRoot(revtree1, src_path)
 
1733
        self.assertRevisionRoot(revtree1, dest_path)
 
1734
 
 
1735
    def test_copy_to_deleted_symlink_in_root(self):
 
1736
        handler, branch = self.get_handler()
 
1737
        src_path = 'a'
 
1738
        dest_path = 'b'
 
1739
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1740
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1741
            expected_added=[(src_path,), (dest_path,)])
 
1742
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1743
            expected_removed=[(dest_path,)],
 
1744
            expected_added=[(dest_path,)])
 
1745
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1746
        self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
 
1747
        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
 
1748
        self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
 
1749
        self.assertRevisionRoot(revtree1, src_path)
 
1750
        self.assertRevisionRoot(revtree1, dest_path)
 
1751
 
 
1752
    def test_copy_to_deleted_file_in_subdir(self):
 
1753
        handler, branch = self.get_handler()
 
1754
        src_path = 'd/a'
 
1755
        dest_path = 'd/b'
 
1756
        handler.process(self.file_command_iter(src_path, dest_path))
 
1757
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1758
            expected_added=[('d',), (src_path,), (dest_path,)])
 
1759
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1760
            expected_removed=[(dest_path,)],
 
1761
            expected_added=[(dest_path,)])
 
1762
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1763
        self.assertContent(branch, revtree1, dest_path, "bbb")
 
1764
        self.assertContent(branch, revtree2, src_path, "aaa")
 
1765
        self.assertContent(branch, revtree2, dest_path, "aaa")
 
1766
 
 
1767
    def test_copy_to_deleted_symlink_in_subdir(self):
 
1768
        handler, branch = self.get_handler()
 
1769
        src_path = 'd/a'
 
1770
        dest_path = 'd/b'
 
1771
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1772
        revtree0, revtree1 = self.assertChanges(branch, 1,
 
1773
            expected_added=[('d',), (src_path,), (dest_path,)])
 
1774
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1775
            expected_removed=[(dest_path,)],
 
1776
            expected_added=[(dest_path,)])
 
1777
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1778
        self.assertSymlinkTarget(branch, revtree1, dest_path, "bbb")
 
1779
        self.assertSymlinkTarget(branch, revtree2, src_path, "aaa")
 
1780
        self.assertSymlinkTarget(branch, revtree2, dest_path, "aaa")
 
1781
 
 
1782
 
 
1783
class TestImportToPackCopyModified(TestCaseForGenericProcessor):
 
1784
    """Test copy of file/symlink already modified in this commit."""
 
1785
 
 
1786
    def file_command_iter(self, src_path, dest_path, kind='file'):
 
1787
 
 
1788
        # Revno 1: create a file or symlink
 
1789
        # Revno 2: modify and copy it
 
1790
        def command_list():
 
1791
            author = ['', 'bugs@a.com', time.time(), time.timezone]
 
1792
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1793
            def files_one():
 
1794
                yield commands.FileModifyCommand(src_path, kind_to_mode(kind, False),
 
1795
                        None, "aaa")
 
1796
            yield commands.CommitCommand('head', '1', author,
 
1797
                committer, "commit 1", None, [], files_one)
 
1798
            def files_two():
 
1799
                yield commands.FileModifyCommand(src_path, kind_to_mode(kind, False),
 
1800
                        None, "bbb")
 
1801
                yield commands.FileCopyCommand(src_path, dest_path)
 
1802
            yield commands.CommitCommand('head', '2', author,
 
1803
                committer, "commit 2", ":1", [], files_two)
 
1804
        return command_list
 
1805
 
 
1806
    def test_copy_of_modified_file_in_root(self):
 
1807
        handler, branch = self.get_handler()
 
1808
        src_path = 'a'
 
1809
        dest_path = 'b'
 
1810
        handler.process(self.file_command_iter(src_path, dest_path))
 
1811
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1812
            expected_modified=[(src_path,)],
 
1813
            expected_added=[(dest_path,)])
 
1814
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1815
        self.assertContent(branch, revtree2, src_path, "bbb")
 
1816
        self.assertContent(branch, revtree2, dest_path, "bbb")
 
1817
        self.assertRevisionRoot(revtree1, src_path)
 
1818
        self.assertRevisionRoot(revtree2, dest_path)
 
1819
 
 
1820
    def test_copy_of_modified_file_in_subdir(self):
 
1821
        handler, branch = self.get_handler()
 
1822
        src_path = 'd/a'
 
1823
        dest_path = 'd/b'
 
1824
        handler.process(self.file_command_iter(src_path, dest_path))
 
1825
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1826
            expected_modified=[(src_path,)],
 
1827
            expected_added=[(dest_path,)])
 
1828
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1829
        self.assertContent(branch, revtree2, src_path, "bbb")
 
1830
        self.assertContent(branch, revtree2, dest_path, "bbb")
 
1831
 
 
1832
    def test_copy_of_modified_file_to_new_dir(self):
 
1833
        handler, branch = self.get_handler()
 
1834
        src_path = 'd1/a'
 
1835
        dest_path = 'd2/a'
 
1836
        handler.process(self.file_command_iter(src_path, dest_path))
 
1837
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1838
            expected_modified=[(src_path,)],
 
1839
            expected_added=[('d2',), (dest_path,)])
 
1840
        self.assertContent(branch, revtree1, src_path, "aaa")
 
1841
        self.assertContent(branch, revtree2, src_path, "bbb")
 
1842
        self.assertContent(branch, revtree2, dest_path, "bbb")
 
1843
 
 
1844
    def test_copy_of_modified_symlink_in_root(self):
 
1845
        handler, branch = self.get_handler()
 
1846
        src_path = 'a'
 
1847
        dest_path = 'b'
 
1848
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1849
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1850
            expected_modified=[(src_path,)],
 
1851
            expected_added=[(dest_path,)])
 
1852
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1853
        self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
 
1854
        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
 
1855
        self.assertRevisionRoot(revtree1, src_path)
 
1856
        self.assertRevisionRoot(revtree2, dest_path)
 
1857
 
 
1858
    def test_copy_of_modified_symlink_in_subdir(self):
 
1859
        handler, branch = self.get_handler()
 
1860
        src_path = 'd/a'
 
1861
        dest_path = 'd/b'
 
1862
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1863
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1864
            expected_modified=[(src_path,)],
 
1865
            expected_added=[(dest_path,)])
 
1866
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1867
        self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
 
1868
        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
 
1869
 
 
1870
    def test_copy_of_modified_symlink_to_new_dir(self):
 
1871
        handler, branch = self.get_handler()
 
1872
        src_path = 'd1/a'
 
1873
        dest_path = 'd2/a'
 
1874
        handler.process(self.file_command_iter(src_path, dest_path, 'symlink'))
 
1875
        revtree1, revtree2 = self.assertChanges(branch, 2,
 
1876
            expected_modified=[(src_path,)],
 
1877
            expected_added=[('d2',), (dest_path,)])
 
1878
        self.assertSymlinkTarget(branch, revtree1, src_path, "aaa")
 
1879
        self.assertSymlinkTarget(branch, revtree2, src_path, "bbb")
 
1880
        self.assertSymlinkTarget(branch, revtree2, dest_path, "bbb")
 
1881
 
 
1882
 
 
1883
class TestImportToPackFileKinds(TestCaseForGenericProcessor):
 
1884
 
 
1885
    def get_command_iter(self, path, kind, content):
 
1886
 
 
1887
        def command_list():
 
1888
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1889
            def files_one():
 
1890
                yield commands.FileModifyCommand(path, kind_to_mode(kind, False),
 
1891
                        None, content)
 
1892
            yield commands.CommitCommand('head', '1', None,
 
1893
                committer, "commit 1", None, [], files_one)
 
1894
        return command_list
 
1895
 
 
1896
    def test_import_plainfile(self):
 
1897
        handler, branch = self.get_handler()
 
1898
        handler.process(self.get_command_iter('foo', 'file', 'aaa'))
 
1899
 
 
1900
    def test_import_symlink(self):
 
1901
        handler, branch = self.get_handler()
 
1902
        handler.process(self.get_command_iter('foo', 'symlink', 'bar'))
 
1903
 
 
1904
 
 
1905
class TestModifyRevertInBranch(TestCaseForGenericProcessor):
 
1906
 
 
1907
    def file_command_iter(self):
 
1908
        # A     add 'foo'
 
1909
        # |\
 
1910
        # | B   modify 'foo'
 
1911
        # | |
 
1912
        # | C   revert 'foo' back to A
 
1913
        # |/
 
1914
        # D     merge 'foo'
 
1915
        def command_list():
 
1916
            committer_a = ['', 'a@elmer.com', time.time(), time.timezone]
 
1917
            committer_b = ['', 'b@elmer.com', time.time(), time.timezone]
 
1918
            committer_c = ['', 'c@elmer.com', time.time(), time.timezone]
 
1919
            committer_d = ['', 'd@elmer.com', time.time(), time.timezone]
 
1920
            def files_one():
 
1921
                yield commands.FileModifyCommand('foo', kind_to_mode('file', False),
 
1922
                        None, "content A\n")
 
1923
            yield commands.CommitCommand('head', '1', None,
 
1924
                committer_a, "commit 1", None, [], files_one)
 
1925
            def files_two():
 
1926
                yield commands.FileModifyCommand('foo', kind_to_mode('file', False),
 
1927
                        None, "content B\n")
 
1928
            yield commands.CommitCommand('head', '2', None,
 
1929
                committer_b, "commit 2", ":1", [], files_two)
 
1930
            def files_three():
 
1931
                yield commands.FileModifyCommand('foo', kind_to_mode('file', False),
 
1932
                        None, "content A\n")
 
1933
            yield commands.CommitCommand('head', '3', None,
 
1934
                committer_c, "commit 3", ":2", [], files_three)
 
1935
            yield commands.CommitCommand('head', '4', None,
 
1936
                committer_d, "commit 4", ":1", [':3'], lambda: [])
 
1937
        return command_list
 
1938
 
 
1939
    def test_modify_revert(self):
 
1940
        handler, branch = self.get_handler()
 
1941
        handler.process(self.file_command_iter())
 
1942
        branch.lock_read()
 
1943
        self.addCleanup(branch.unlock)
 
1944
        rev_d = branch.last_revision()
 
1945
        rev_a, rev_c = branch.repository.get_parent_map([rev_d])[rev_d]
 
1946
        rev_b = branch.repository.get_parent_map([rev_c])[rev_c][0]
 
1947
        rtree_a, rtree_b, rtree_c, rtree_d = branch.repository.revision_trees([
 
1948
            rev_a, rev_b, rev_c, rev_d])
 
1949
        foo_id = rtree_a.path2id('foo')
 
1950
        self.assertEqual(rev_a, rtree_a.get_file_revision(foo_id))
 
1951
        self.assertEqual(rev_b, rtree_b.get_file_revision(foo_id))
 
1952
        self.assertEqual(rev_c, rtree_c.get_file_revision(foo_id))
 
1953
        self.assertEqual(rev_c, rtree_d.get_file_revision(foo_id))
 
1954
 
 
1955
 
 
1956
class TestCommitCommands(TestCaseForGenericProcessor):
 
1957
 
 
1958
    def test_non_utf8_commit_message(self):
 
1959
        handler, branch = self.get_handler()
 
1960
        def files_one():
 
1961
            yield commands.FileModifyCommand('a',
 
1962
                kind_to_mode('file', False), None, "data")
 
1963
        def command_list():
 
1964
            committer = ['', 'elmer@a.com', time.time(), time.timezone]
 
1965
            yield commands.CommitCommand('head', '1', None,
 
1966
                committer, 'This is a funky character: \x83', None, [],
 
1967
                files_one)
 
1968
        handler.process(command_list)
 
1969
        rev = branch.repository.get_revision(branch.last_revision())
 
1970
        self.assertEquals(u"This is a funky character: \ufffd", rev.message)
 
1971
 
 
1972
 
 
1973
class TestAddNonUtf8InBranch(TestCaseForGenericProcessor):
 
1974
 
 
1975
    def file_command_iter(self):
 
1976
        # A     add 'foo\x83'
 
1977
        def command_list():
 
1978
            committer_a = ['', 'a@elmer.com', time.time(), time.timezone]
 
1979
            def files_one():
 
1980
                yield commands.FileModifyCommand(
 
1981
                    'foo\x83', kind_to_mode('file', False), None, "content A\n")
 
1982
            yield commands.CommitCommand('head', '1', None,
 
1983
                committer_a, "commit 1", None, [], files_one)
 
1984
        return command_list
 
1985
 
 
1986
    def test_add(self):
 
1987
        handler, branch = self.get_handler()
 
1988
        handler.process(self.file_command_iter())
 
1989
        branch.lock_read()
 
1990
        self.addCleanup(branch.unlock)
 
1991
        rev_a = branch.last_revision()
 
1992
        rtree_a = branch.repository.revision_tree(rev_a)
 
1993
        foo_id = rtree_a.path2id(u'foo\ufffd')
 
1994
        self.assertEqual(rev_a, rtree_a.get_file_revision(foo_id))