/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/intertree_implementations/test_compare.py

First attempt to merge .dev and resolve the conflicts (but tests are 
failing)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 by Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
"""Tests for the InterTree.compare() function."""
18
18
 
19
 
from bzrlib import errors
 
19
import os
 
20
import shutil
 
21
 
 
22
from bzrlib import errors, tests, workingtree_4
 
23
from bzrlib.osutils import file_kind, has_symlinks
 
24
from bzrlib.tests import TestNotApplicable
20
25
from bzrlib.tests.intertree_implementations import TestCaseWithTwoTrees
21
26
 
 
27
# TODO: test the include_root option.
 
28
# TODO: test that renaming a directory x->y does not emit a rename for the
 
29
#       child x/a->y/a.
 
30
# TODO: test that renaming a directory x-> does not emit a rename for the child
 
31
#        x/a -> y/a when a supplied_files argument gives either 'x/' or 'y/a'
 
32
#        -> that is, when the renamed parent is not processed by the function.
 
33
# TODO: test items are only emitted once when a specific_files list names a dir
 
34
#       whose parent is now a child.
 
35
# TODO: test specific_files when the target tree has a file and the source a
 
36
#       dir with children, same id and same path. 
 
37
# TODO: test comparisons between trees with different root ids. mbp 20070301
 
38
#
 
39
# TODO: More comparisons between trees with subtrees in different states.
 
40
#
 
41
# TODO: Many tests start out by setting the tree roots ids the same, maybe
 
42
#       that should just be the default for these tests, by changing
 
43
#       make_branch_and_tree.  mbp 20070307
22
44
 
23
45
class TestCompare(TestCaseWithTwoTrees):
24
46
 
25
47
    def test_compare_empty_trees(self):
26
48
        tree1 = self.make_branch_and_tree('1')
27
49
        tree2 = self.make_to_branch_and_tree('2')
 
50
        tree2.set_root_id(tree1.get_root_id())
28
51
        tree1 = self.get_tree_no_parents_no_content(tree1)
29
 
        tree2 = self.get_to_tree_no_parents_no_content(tree2)
 
52
        tree2 = self.get_tree_no_parents_no_content(tree2)
 
53
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
30
54
        d = self.intertree_class(tree1, tree2).compare()
31
55
        self.assertEqual([], d.added)
32
56
        self.assertEqual([], d.modified)
37
61
    def test_empty_to_abc_content(self):
38
62
        tree1 = self.make_branch_and_tree('1')
39
63
        tree2 = self.make_to_branch_and_tree('2')
 
64
        tree2.set_root_id(tree1.get_root_id())
40
65
        tree1 = self.get_tree_no_parents_no_content(tree1)
41
 
        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
 
66
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
67
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
42
68
        d = self.intertree_class(tree1, tree2).compare()
43
69
        self.assertEqual([('a', 'a-id', 'file'),
44
70
                          ('b', 'b-id', 'directory'),
49
75
        self.assertEqual([], d.renamed)
50
76
        self.assertEqual([], d.unchanged)
51
77
 
 
78
    def test_dangling(self):
 
79
        # This test depends on the ability for some trees to have a difference
 
80
        # between a 'versioned present' and 'versioned not present' (aka
 
81
        # dangling) file. In this test there are two trees each with a separate
 
82
        # dangling file, and the dangling files should be considered absent for
 
83
        # the test.
 
84
        tree1 = self.make_branch_and_tree('1')
 
85
        tree2 = self.make_to_branch_and_tree('2')
 
86
        tree2.set_root_id(tree1.get_root_id())
 
87
        self.build_tree(['2/a'])
 
88
        tree2.add('a')
 
89
        os.unlink('2/a')
 
90
        self.build_tree(['1/b'])
 
91
        tree1.add('b')
 
92
        os.unlink('1/b')
 
93
        # the conversion to test trees here will leave the trees intact for the
 
94
        # default intertree, but may perform a commit for other tree types,
 
95
        # which may reduce the validity of the test. XXX: Think about how to
 
96
        # address this.
 
97
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
98
        d = self.intertree_class(tree1, tree2).compare()
 
99
        self.assertEqual([], d.added)
 
100
        self.assertEqual([], d.modified)
 
101
        self.assertEqual([], d.removed)
 
102
        self.assertEqual([], d.renamed)
 
103
        self.assertEqual([], d.unchanged)
 
104
 
52
105
    def test_abc_content_to_empty(self):
53
106
        tree1 = self.make_branch_and_tree('1')
54
107
        tree2 = self.make_to_branch_and_tree('2')
 
108
        tree2.set_root_id(tree1.get_root_id())
55
109
        tree1 = self.get_tree_no_parents_abc_content(tree1)
56
 
        tree2 = self.get_to_tree_no_parents_no_content(tree2)
 
110
        tree2 = self.get_tree_no_parents_no_content(tree2)
 
111
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
57
112
        d = self.intertree_class(tree1, tree2).compare()
58
113
        self.assertEqual([], d.added)
59
114
        self.assertEqual([], d.modified)
67
122
    def test_content_modification(self):
68
123
        tree1 = self.make_branch_and_tree('1')
69
124
        tree2 = self.make_to_branch_and_tree('2')
 
125
        tree2.set_root_id(tree1.get_root_id())
70
126
        tree1 = self.get_tree_no_parents_abc_content(tree1)
71
 
        tree2 = self.get_to_tree_no_parents_abc_content_2(tree2)
 
127
        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
 
128
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
72
129
        d = self.intertree_class(tree1, tree2).compare()
73
130
        self.assertEqual([], d.added)
74
131
        self.assertEqual([('a', 'a-id', 'file', True, False)], d.modified)
79
136
    def test_meta_modification(self):
80
137
        tree1 = self.make_branch_and_tree('1')
81
138
        tree2 = self.make_to_branch_and_tree('2')
 
139
        tree2.set_root_id(tree1.get_root_id())
82
140
        tree1 = self.get_tree_no_parents_abc_content(tree1)
83
 
        tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
 
141
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
 
142
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
84
143
        d = self.intertree_class(tree1, tree2).compare()
85
144
        self.assertEqual([], d.added)
86
145
        self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
91
150
    def test_file_rename(self):
92
151
        tree1 = self.make_branch_and_tree('1')
93
152
        tree2 = self.make_to_branch_and_tree('2')
 
153
        tree2.set_root_id(tree1.get_root_id())
94
154
        tree1 = self.get_tree_no_parents_abc_content(tree1)
95
 
        tree2 = self.get_to_tree_no_parents_abc_content_4(tree2)
 
155
        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
 
156
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
96
157
        d = self.intertree_class(tree1, tree2).compare()
97
158
        self.assertEqual([], d.added)
98
159
        self.assertEqual([], d.modified)
103
164
    def test_file_rename_and_modification(self):
104
165
        tree1 = self.make_branch_and_tree('1')
105
166
        tree2 = self.make_to_branch_and_tree('2')
 
167
        tree2.set_root_id(tree1.get_root_id())
106
168
        tree1 = self.get_tree_no_parents_abc_content(tree1)
107
 
        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
 
169
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
 
170
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
108
171
        d = self.intertree_class(tree1, tree2).compare()
109
172
        self.assertEqual([], d.added)
110
173
        self.assertEqual([], d.modified)
115
178
    def test_file_rename_and_meta_modification(self):
116
179
        tree1 = self.make_branch_and_tree('1')
117
180
        tree2 = self.make_to_branch_and_tree('2')
 
181
        tree2.set_root_id(tree1.get_root_id())
118
182
        tree1 = self.get_tree_no_parents_abc_content(tree1)
119
 
        tree2 = self.get_to_tree_no_parents_abc_content_6(tree2)
 
183
        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
 
184
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
120
185
        d = self.intertree_class(tree1, tree2).compare()
121
186
        self.assertEqual([], d.added)
122
187
        self.assertEqual([], d.modified)
127
192
    def test_empty_to_abc_content_a_only(self):
128
193
        tree1 = self.make_branch_and_tree('1')
129
194
        tree2 = self.make_to_branch_and_tree('2')
 
195
        tree2.set_root_id(tree1.get_root_id())
130
196
        tree1 = self.get_tree_no_parents_no_content(tree1)
131
 
        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
 
197
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
198
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
132
199
        d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
133
200
        self.assertEqual([('a', 'a-id', 'file')], d.added)
134
201
        self.assertEqual([], d.modified)
140
207
        tree1 = self.make_branch_and_tree('1')
141
208
        tree2 = self.make_to_branch_and_tree('2')
142
209
        tree1 = self.get_tree_no_parents_no_content(tree1)
143
 
        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
 
210
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
211
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
144
212
        d = self.intertree_class(tree1, tree2).compare(
145
213
            specific_files=['a', 'b/c'])
146
214
        self.assertEqual(
156
224
        tree1 = self.make_branch_and_tree('1')
157
225
        tree2 = self.make_to_branch_and_tree('2')
158
226
        tree1 = self.get_tree_no_parents_no_content(tree1)
159
 
        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
 
227
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
228
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
160
229
        d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
161
230
        self.assertEqual(
162
231
            [('b', 'b-id', 'directory'),('b/c', 'c-id', 'file')],
171
240
        tree1 = self.make_branch_and_tree('1')
172
241
        tree2 = self.make_to_branch_and_tree('2')
173
242
        tree1 = self.get_tree_no_parents_abc_content(tree1)
174
 
        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
 
243
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
 
244
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
175
245
        d = self.intertree_class(tree1, tree2).compare(want_unchanged=True)
176
246
        self.assertEqual([], d.added)
177
247
        self.assertEqual([], d.modified)
186
256
        tree1 = self.make_branch_and_tree('1')
187
257
        tree2 = self.make_to_branch_and_tree('2')
188
258
        tree1 = self.get_tree_no_parents_abc_content(tree1)
189
 
        tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
 
259
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
 
260
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
261
        d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
190
262
        # the type of tree-3 does not matter - it is used as a lookup, not
191
 
        # a dispatch
 
263
        # a dispatch. XXX: For dirstate it does speak to the optimisability of
 
264
        # the lookup, in merged trees it can be fast-pathed. We probably want
 
265
        # two tests: one as is, and one with it as a pending merge.
192
266
        tree3 = self.make_branch_and_tree('3')
193
267
        tree3 = self.get_tree_no_parents_abc_content_6(tree3)
 
268
        tree3.lock_read()
 
269
        self.addCleanup(tree3.unlock)
194
270
        # tree 3 has 'e' which is 'c-id'. Tree 1 has c-id at b/c, and Tree 2
195
271
        # has c-id at b/c with its exec flag toggled.
196
272
        # without extra_trees, we should get no modifications from this
215
291
        tree1 = self.make_branch_and_tree('1')
216
292
        tree2 = self.make_to_branch_and_tree('2')
217
293
        tree1 = self.get_tree_no_parents_no_content(tree1)
218
 
        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
 
294
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
295
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
219
296
        self.assertRaises(errors.PathsNotVersionedError, 
220
297
            self.intertree_class(tree1, tree2).compare,
221
298
            specific_files=['d'],
222
299
            require_versioned=True)
 
300
 
 
301
    def test_default_ignores_unversioned_files(self):
 
302
        tree1 = self.make_branch_and_tree('tree1')
 
303
        tree2 = self.make_to_branch_and_tree('tree2')
 
304
        tree2.set_root_id(tree1.get_root_id())
 
305
        self.build_tree(['tree1/a', 'tree1/c',
 
306
                         'tree2/a', 'tree2/b', 'tree2/c'])
 
307
        tree1.add(['a', 'c'], ['a-id', 'c-id'])
 
308
        tree2.add(['a', 'c'], ['a-id', 'c-id'])
 
309
 
 
310
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
311
        d = self.intertree_class(tree1, tree2).compare()
 
312
        self.assertEqual([], d.added)
 
313
        self.assertEqual([(u'a', 'a-id', 'file', True, False),
 
314
            (u'c', 'c-id', 'file', True, False)], d.modified)
 
315
        self.assertEqual([], d.removed)
 
316
        self.assertEqual([], d.renamed)
 
317
        self.assertEqual([], d.unchanged)
 
318
        self.assertEqual([], d.unversioned)
 
319
 
 
320
    def test_unversioned_paths_in_tree(self):
 
321
        tree1 = self.make_branch_and_tree('tree1')
 
322
        tree2 = self.make_to_branch_and_tree('tree2')
 
323
        tree2.set_root_id(tree1.get_root_id())
 
324
        self.build_tree(['tree2/file', 'tree2/dir/'])
 
325
        if has_symlinks():
 
326
            os.symlink('target', 'tree2/link')
 
327
            links_supported = True
 
328
        else:
 
329
            links_supported = False
 
330
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
331
        d = self.intertree_class(tree1, tree2).compare(want_unversioned=True)
 
332
        self.assertEqual([], d.added)
 
333
        self.assertEqual([], d.modified)
 
334
        self.assertEqual([], d.removed)
 
335
        self.assertEqual([], d.renamed)
 
336
        self.assertEqual([], d.unchanged)
 
337
        expected_unversioned = [(u'dir', None, 'directory'),
 
338
                                (u'file', None, 'file')]
 
339
        if links_supported:
 
340
            expected_unversioned.append((u'link', None, 'symlink'))
 
341
        self.assertEqual(expected_unversioned, d.unversioned)
 
342
 
 
343
 
 
344
class TestIterChanges(TestCaseWithTwoTrees):
 
345
    """Test the comparison iterator"""
 
346
 
 
347
    def do_iter_changes(self, tree1, tree2, **extra_args):
 
348
        """Helper to run iter_changes from tree1 to tree2.
 
349
        
 
350
        :param tree1, tree2:  The source and target trees. These will be locked
 
351
            automatically.
 
352
        :param **extra_args: Extra args to pass to iter_changes. This is not
 
353
            inspected by this test helper.
 
354
        """
 
355
        tree1.lock_read()
 
356
        tree2.lock_read()
 
357
        try:
 
358
            # sort order of output is not strictly defined
 
359
            return sorted(self.intertree_class(tree1, tree2)
 
360
                .iter_changes(**extra_args))
 
361
        finally:
 
362
            tree1.unlock()
 
363
            tree2.unlock()
 
364
 
 
365
    def mutable_trees_to_locked_test_trees(self, tree1, tree2):
 
366
        """Convert the working trees into test trees.
 
367
 
 
368
        Read lock them, and add the unlock to the cleanup.
 
369
        """
 
370
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
371
        tree1.lock_read()
 
372
        self.addCleanup(tree1.unlock)
 
373
        tree2.lock_read()
 
374
        self.addCleanup(tree2.unlock)
 
375
        return tree1, tree2
 
376
 
 
377
    def make_tree_with_special_names(self):
 
378
        """Create a tree with filenames chosen to exercise the walk order."""
 
379
        tree1 = self.make_branch_and_tree('tree1')
 
380
        tree2 = self.make_to_branch_and_tree('tree2')
 
381
        tree2.set_root_id(tree1.get_root_id())
 
382
        paths, path_ids = self._create_special_names(tree2, 'tree2')
 
383
        tree2.commit('initial', rev_id='rev-1')
 
384
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
385
        return (tree1, tree2, paths, path_ids)
 
386
 
 
387
    def make_trees_with_special_names(self):
 
388
        """Both trees will use the special names.
 
389
 
 
390
        But the contents will differ for each file.
 
391
        """
 
392
        tree1 = self.make_branch_and_tree('tree1')
 
393
        tree2 = self.make_to_branch_and_tree('tree2')
 
394
        tree2.set_root_id(tree1.get_root_id())
 
395
        paths, path_ids = self._create_special_names(tree1, 'tree1')
 
396
        paths, path_ids = self._create_special_names(tree2, 'tree2')
 
397
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
398
        return (tree1, tree2, paths, path_ids)
 
399
 
 
400
    def _create_special_names(self, tree, base_path):
 
401
        """Create a tree with paths that expose differences in sort orders."""
 
402
        # Each directory will have a single file named 'f' inside
 
403
        dirs = ['a',
 
404
                'a-a',
 
405
                'a/a',
 
406
                'a/a-a',
 
407
                'a/a/a',
 
408
                'a/a/a-a',
 
409
                'a/a/a/a',
 
410
                'a/a/a/a-a',
 
411
                'a/a/a/a/a',
 
412
               ]
 
413
        with_slashes = []
 
414
        paths = []
 
415
        path_ids = []
 
416
        for d in dirs:
 
417
            with_slashes.append(base_path + '/' + d + '/')
 
418
            with_slashes.append(base_path + '/' + d + '/f')
 
419
            paths.append(d)
 
420
            paths.append(d+'/f')
 
421
            path_ids.append(d.replace('/', '_') + '-id')
 
422
            path_ids.append(d.replace('/', '_') + '_f-id')
 
423
        self.build_tree(with_slashes)
 
424
        tree.add(paths, path_ids)
 
425
        return paths, path_ids
 
426
 
 
427
    def test_compare_empty_trees(self):
 
428
        tree1 = self.make_branch_and_tree('1')
 
429
        tree2 = self.make_to_branch_and_tree('2')
 
430
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
431
        tree2 = self.get_tree_no_parents_no_content(tree2)
 
432
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
433
        self.assertEqual([], self.do_iter_changes(tree1, tree2))
 
434
 
 
435
    def added(self, tree, file_id):
 
436
        entry = tree.inventory[file_id]
 
437
        path = tree.id2path(file_id)
 
438
        return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
 
439
                (None, entry.name), (None, entry.kind),
 
440
                (None, entry.executable))
 
441
 
 
442
    def content_changed(self, tree, file_id):
 
443
        entry = tree.inventory[file_id]
 
444
        path = tree.id2path(file_id)
 
445
        return (file_id, (path, path), True, (True, True), (entry.parent_id, entry.parent_id),
 
446
                (entry.name, entry.name), (entry.kind, entry.kind),
 
447
                (entry.executable, entry.executable))
 
448
 
 
449
    def kind_changed(self, from_tree, to_tree, file_id):
 
450
        old_entry = from_tree.inventory[file_id]
 
451
        new_entry = to_tree.inventory[file_id]
 
452
        path = to_tree.id2path(file_id)
 
453
        from_path = from_tree.id2path(file_id)
 
454
        return (file_id, (from_path, path), True, (True, True), (old_entry.parent_id, new_entry.parent_id),
 
455
                (old_entry.name, new_entry.name), (old_entry.kind, new_entry.kind),
 
456
                (old_entry.executable, new_entry.executable))
 
457
 
 
458
    def missing(self, file_id, from_path, to_path, parent_id, kind):
 
459
        _, from_basename = os.path.split(from_path)
 
460
        _, to_basename = os.path.split(to_path)
 
461
        # missing files have both paths, but no kind.
 
462
        return (file_id, (from_path, to_path), True, (True, True),
 
463
            (parent_id, parent_id),
 
464
            (from_basename, to_basename), (kind, None), (False, False))
 
465
 
 
466
    def deleted(self, tree, file_id):
 
467
        entry = tree.inventory[file_id]
 
468
        path = tree.id2path(file_id)
 
469
        return (file_id, (path, None), True, (True, False), (entry.parent_id, None),
 
470
                (entry.name, None), (entry.kind, None),
 
471
                (entry.executable, None))
 
472
 
 
473
    def renamed(self, from_tree, to_tree, file_id, content_changed):
 
474
        from_entry = from_tree.inventory[file_id]
 
475
        to_entry = to_tree.inventory[file_id]
 
476
        from_path = from_tree.id2path(file_id)
 
477
        to_path = to_tree.id2path(file_id)
 
478
        return (file_id, (from_path, to_path), content_changed, (True, True),
 
479
            (from_entry.parent_id, to_entry.parent_id),
 
480
            (from_entry.name, to_entry.name),
 
481
            (from_entry.kind, to_entry.kind),
 
482
            (from_entry.executable, to_entry.executable))
 
483
 
 
484
    def unchanged(self, tree, file_id):
 
485
        entry = tree.inventory[file_id]
 
486
        parent = entry.parent_id
 
487
        name = entry.name
 
488
        kind = entry.kind
 
489
        executable = entry.executable
 
490
        path = tree.id2path(file_id)
 
491
        return (file_id, (path, path), False, (True, True),
 
492
               (parent, parent), (name, name), (kind, kind),
 
493
               (executable, executable))
 
494
 
 
495
    def unversioned(self, tree, path):
 
496
        """Create an unversioned result."""
 
497
        _, basename = os.path.split(path)
 
498
        kind = file_kind(tree.abspath(path))
 
499
        return (None, (None, path), True, (False, False), (None, None),
 
500
                (None, basename), (None, kind),
 
501
                (None, False))
 
502
 
 
503
    def test_empty_to_abc_content(self):
 
504
        tree1 = self.make_branch_and_tree('1')
 
505
        tree2 = self.make_to_branch_and_tree('2')
 
506
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
507
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
508
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
509
        expected_results = sorted([
 
510
            self.added(tree2, 'root-id'),
 
511
            self.added(tree2, 'a-id'),
 
512
            self.added(tree2, 'b-id'),
 
513
            self.added(tree2, 'c-id'),
 
514
            self.deleted(tree1, 'empty-root-id')])
 
515
        self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
 
516
 
 
517
    def test_empty_specific_files(self):
 
518
        tree1 = self.make_branch_and_tree('1')
 
519
        tree2 = self.make_to_branch_and_tree('2')
 
520
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
521
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
522
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
523
        self.assertEqual([],
 
524
            self.do_iter_changes(tree1, tree2, specific_files=[]))
 
525
 
 
526
    def test_no_specific_files(self):
 
527
        tree1 = self.make_branch_and_tree('1')
 
528
        tree2 = self.make_to_branch_and_tree('2')
 
529
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
530
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
531
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
532
        expected_results = sorted([
 
533
            self.added(tree2, 'root-id'),
 
534
            self.added(tree2, 'a-id'),
 
535
            self.added(tree2, 'b-id'),
 
536
            self.added(tree2, 'c-id'),
 
537
            self.deleted(tree1, 'empty-root-id')])
 
538
        self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
 
539
 
 
540
    def test_empty_to_abc_content_a_only(self):
 
541
        tree1 = self.make_branch_and_tree('1')
 
542
        tree2 = self.make_to_branch_and_tree('2')
 
543
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
544
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
545
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
546
        self.assertEqual(
 
547
            [self.added(tree2, 'a-id')],
 
548
            self.do_iter_changes(tree1, tree2, specific_files=['a']))
 
549
 
 
550
    def test_abc_content_to_empty_to_abc_content_a_only(self):
 
551
        tree1 = self.make_branch_and_tree('1')
 
552
        tree2 = self.make_to_branch_and_tree('2')
 
553
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
554
        tree2 = self.get_tree_no_parents_no_content(tree2)
 
555
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
556
        self.assertEqual(
 
557
            [self.deleted(tree1, 'a-id')],
 
558
            self.do_iter_changes(tree1, tree2, specific_files=['a']))
 
559
 
 
560
    def test_empty_to_abc_content_a_and_c_only(self):
 
561
        tree1 = self.make_branch_and_tree('1')
 
562
        tree2 = self.make_to_branch_and_tree('2')
 
563
        tree1 = self.get_tree_no_parents_no_content(tree1)
 
564
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
565
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
566
        expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
 
567
        self.assertEqual(expected_result,
 
568
            self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
 
569
 
 
570
    def test_abc_content_to_empty(self):
 
571
        tree1 = self.make_branch_and_tree('1')
 
572
        tree2 = self.make_to_branch_and_tree('2')
 
573
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
574
        tree2 = self.get_tree_no_parents_no_content(tree2)
 
575
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
576
        def deleted(file_id):
 
577
            entry = tree1.inventory[file_id]
 
578
            path = tree1.id2path(file_id)
 
579
            return (file_id, (path, None), True, (True, False),
 
580
                    (entry.parent_id, None),
 
581
                    (entry.name, None), (entry.kind, None),
 
582
                    (entry.executable, None))
 
583
        expected_results = sorted([
 
584
            self.added(tree2, 'empty-root-id'),
 
585
            deleted('root-id'), deleted('a-id'),
 
586
            deleted('b-id'), deleted('c-id')])
 
587
        self.assertEqual(
 
588
            expected_results,
 
589
            self.do_iter_changes(tree1, tree2))
 
590
 
 
591
    def test_content_modification(self):
 
592
        tree1 = self.make_branch_and_tree('1')
 
593
        tree2 = self.make_to_branch_and_tree('2')
 
594
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
595
        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
 
596
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
597
        root_id = tree1.path2id('')
 
598
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
 
599
                           (root_id, root_id), ('a', 'a'),
 
600
                           ('file', 'file'), (False, False))],
 
601
                         self.do_iter_changes(tree1, tree2))
 
602
 
 
603
    def test_meta_modification(self):
 
604
        tree1 = self.make_branch_and_tree('1')
 
605
        tree2 = self.make_to_branch_and_tree('2')
 
606
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
607
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
 
608
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
609
        self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
 
610
                           ('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
 
611
                          (False, True))],
 
612
                         self.do_iter_changes(tree1, tree2))
 
613
 
 
614
    def test_empty_dir(self):
 
615
        """an empty dir should not cause glitches to surrounding files."""
 
616
        tree1 = self.make_branch_and_tree('1')
 
617
        tree2 = self.make_to_branch_and_tree('2')
 
618
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
619
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
620
        # the pathname is chosen to fall between 'a' and 'b'.
 
621
        self.build_tree(['1/a-empty/', '2/a-empty/'])
 
622
        tree1.add(['a-empty'], ['a-empty'])
 
623
        tree2.add(['a-empty'], ['a-empty'])
 
624
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
625
        expected = []
 
626
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
627
 
 
628
    def test_file_rename(self):
 
629
        tree1 = self.make_branch_and_tree('1')
 
630
        tree2 = self.make_to_branch_and_tree('2')
 
631
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
632
        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
 
633
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
634
        root_id = tree1.path2id('')
 
635
        self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
 
636
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
 
637
                           (False, False))],
 
638
                         self.do_iter_changes(tree1, tree2))
 
639
 
 
640
    def test_file_rename_and_modification(self):
 
641
        tree1 = self.make_branch_and_tree('1')
 
642
        tree2 = self.make_to_branch_and_tree('2')
 
643
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
644
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
 
645
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
646
        root_id = tree1.path2id('')
 
647
        self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
 
648
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
 
649
                           (False, False))],
 
650
                         self.do_iter_changes(tree1, tree2))
 
651
 
 
652
    def test_file_rename_and_meta_modification(self):
 
653
        tree1 = self.make_branch_and_tree('1')
 
654
        tree2 = self.make_to_branch_and_tree('2')
 
655
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
656
        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
 
657
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
658
        root_id = tree1.path2id('')
 
659
        self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
 
660
                           ('b-id', root_id), ('c', 'e'), ('file', 'file'),
 
661
                           (False, True))],
 
662
                         self.do_iter_changes(tree1, tree2))
 
663
 
 
664
    def test_missing_in_target(self):
 
665
        """Test with the target files versioned but absent from disk."""
 
666
        tree1 = self.make_branch_and_tree('1')
 
667
        tree2 = self.make_to_branch_and_tree('2')
 
668
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
669
        tree2 = self.get_tree_no_parents_abc_content(tree2)
 
670
        os.unlink('2/a')
 
671
        shutil.rmtree('2/b')
 
672
        # TODO ? have a symlink here?
 
673
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
674
        root_id = tree1.path2id('')
 
675
        expected = sorted([
 
676
            self.missing('a-id', 'a', 'a', root_id, 'file'),
 
677
            self.missing('b-id', 'b', 'b', root_id, 'directory'),
 
678
            self.missing('c-id', 'b/c', 'b/c', 'b-id', 'file'),
 
679
            ])
 
680
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
681
 
 
682
    def test_missing_and_renamed(self):
 
683
        tree1 = self.make_branch_and_tree('tree1')
 
684
        tree2 = self.make_to_branch_and_tree('tree2')
 
685
        tree2.set_root_id(tree1.get_root_id())
 
686
        self.build_tree(['tree1/file'])
 
687
        tree1.add(['file'], ['file-id'])
 
688
        self.build_tree(['tree2/directory/'])
 
689
        tree2.add(['directory'], ['file-id'])
 
690
        os.rmdir('tree2/directory')
 
691
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
692
 
 
693
        root_id = tree1.path2id('')
 
694
        expected = sorted([
 
695
            self.missing('file-id', 'file', 'directory', root_id, 'file'),
 
696
            ])
 
697
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
698
 
 
699
    def test_only_in_source_and_missing(self):
 
700
        tree1 = self.make_branch_and_tree('tree1')
 
701
        tree2 = self.make_to_branch_and_tree('tree2')
 
702
        tree2.set_root_id(tree1.get_root_id())
 
703
        self.build_tree(['tree1/file'])
 
704
        tree1.add(['file'], ['file-id'])
 
705
        os.unlink('tree1/file')
 
706
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
707
        root_id = tree1.path2id('')
 
708
        if not tree1.path2id('file'):
 
709
            # The locked test trees conversion could not preserve the missing
 
710
            # file status. This is normal (e.g. InterDirstateTree falls back
 
711
            # to InterTree if the basis is not a DirstateRevisionTree, and
 
712
            # revision trees cannot have missing files. 
 
713
            raise TestNotApplicable()
 
714
        expected = [('file-id', ('file', None), False, (True, False),
 
715
            (root_id, None), ('file', None), (None, None), (False, None))]
 
716
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
717
 
 
718
    def test_only_in_target_and_missing(self):
 
719
        tree1 = self.make_branch_and_tree('tree1')
 
720
        tree2 = self.make_to_branch_and_tree('tree2')
 
721
        tree2.set_root_id(tree1.get_root_id())
 
722
        self.build_tree(['tree2/file'])
 
723
        tree2.add(['file'], ['file-id'])
 
724
        os.unlink('tree2/file')
 
725
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
726
        root_id = tree1.path2id('')
 
727
        expected = [('file-id', (None, 'file'), False, (False, True),
 
728
            (None, root_id), (None, 'file'), (None, None), (None, False))]
 
729
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
730
 
 
731
    def test_unchanged_with_renames_and_modifications(self):
 
732
        """want_unchanged should generate a list of unchanged entries."""
 
733
        tree1 = self.make_branch_and_tree('1')
 
734
        tree2 = self.make_to_branch_and_tree('2')
 
735
        tree1 = self.get_tree_no_parents_abc_content(tree1)
 
736
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
 
737
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
738
        root_id = tree1.path2id('')
 
739
 
 
740
        self.assertEqual(sorted([self.unchanged(tree1, root_id),
 
741
            self.unchanged(tree1, 'b-id'),
 
742
            ('a-id', ('a', 'd'), True, (True, True),
 
743
             (root_id, root_id), ('a', 'd'), ('file', 'file'),
 
744
            (False, False)), self.unchanged(tree1, 'c-id')]),
 
745
            self.do_iter_changes(tree1, tree2, include_unchanged=True))
 
746
 
 
747
    def test_compare_subtrees(self):
 
748
        tree1 = self.make_branch_and_tree('1')
 
749
        if not tree1.supports_tree_reference():
 
750
            return
 
751
        tree1.set_root_id('root-id')
 
752
        subtree1 = self.make_branch_and_tree('1/sub')
 
753
        subtree1.set_root_id('subtree-id')
 
754
        tree1.add_reference(subtree1)
 
755
 
 
756
        tree2 = self.make_to_branch_and_tree('2')
 
757
        if not tree2.supports_tree_reference():
 
758
            return
 
759
        tree2.set_root_id('root-id')
 
760
        subtree2 = self.make_to_branch_and_tree('2/sub')
 
761
        subtree2.set_root_id('subtree-id')
 
762
        tree2.add_reference(subtree2)
 
763
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
764
 
 
765
        self.assertEqual([], list(tree2.iter_changes(tree1)))
 
766
        subtree1.commit('commit', rev_id='commit-a')
 
767
        self.assertEqual([
 
768
            ('root-id',
 
769
             (u'', u''),
 
770
             False,
 
771
             (True, True),
 
772
             (None, None),
 
773
             (u'', u''),
 
774
             ('directory', 'directory'),
 
775
             (False, False)),
 
776
            ('subtree-id',
 
777
             ('sub', 'sub',),
 
778
             False,
 
779
             (True, True),
 
780
             ('root-id', 'root-id'),
 
781
             ('sub', 'sub'),
 
782
             ('tree-reference', 'tree-reference'),
 
783
             (False, False))],
 
784
                         list(tree2.iter_changes(tree1,
 
785
                             include_unchanged=True)))
 
786
 
 
787
    def test_disk_in_subtrees_skipped(self):
 
788
        """subtrees are considered not-in-the-current-tree.
 
789
        
 
790
        This test tests the trivial case, where the basis has no paths in the
 
791
        current trees subtree.
 
792
        """
 
793
        tree1 = self.make_branch_and_tree('1')
 
794
        tree1.set_root_id('root-id')
 
795
        tree2 = self.make_to_branch_and_tree('2')
 
796
        if not tree2.supports_tree_reference():
 
797
            return
 
798
        tree2.set_root_id('root-id')
 
799
        subtree2 = self.make_to_branch_and_tree('2/sub')
 
800
        subtree2.set_root_id('subtree-id')
 
801
        tree2.add(['sub'], ['subtree-id'])
 
802
        self.build_tree(['2/sub/file'])
 
803
        subtree2.add(['file'])
 
804
 
 
805
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
806
        # this should filter correctly from above
 
807
        self.assertEqual([self.added(tree2, 'subtree-id')],
 
808
            self.do_iter_changes(tree1, tree2, want_unversioned=True))
 
809
        # and when the path is named
 
810
        self.assertEqual([self.added(tree2, 'subtree-id')],
 
811
            self.do_iter_changes(tree1, tree2, specific_files=['sub'],
 
812
                want_unversioned=True))
 
813
 
 
814
    def test_default_ignores_unversioned_files(self):
 
815
        tree1 = self.make_branch_and_tree('tree1')
 
816
        tree2 = self.make_to_branch_and_tree('tree2')
 
817
        tree2.set_root_id(tree1.get_root_id())
 
818
        self.build_tree(['tree1/a', 'tree1/c',
 
819
                         'tree2/a', 'tree2/b', 'tree2/c'])
 
820
        tree1.add(['a', 'c'], ['a-id', 'c-id'])
 
821
        tree2.add(['a', 'c'], ['a-id', 'c-id'])
 
822
 
 
823
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
824
 
 
825
        # We should ignore the fact that 'b' exists in tree-2
 
826
        # because the want_unversioned parameter was not given.
 
827
        expected = sorted([
 
828
            self.content_changed(tree2, 'a-id'),
 
829
            self.content_changed(tree2, 'c-id'),
 
830
            ])
 
831
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
832
 
 
833
    def test_unversioned_paths_in_tree(self):
 
834
        tree1 = self.make_branch_and_tree('tree1')
 
835
        tree2 = self.make_to_branch_and_tree('tree2')
 
836
        tree2.set_root_id(tree1.get_root_id())
 
837
        self.build_tree(['tree2/file', 'tree2/dir/'])
 
838
        if has_symlinks():
 
839
            os.symlink('target', 'tree2/link')
 
840
            links_supported = True
 
841
        else:
 
842
            links_supported = False
 
843
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
844
        expected = [
 
845
            self.unversioned(tree2, 'file'),
 
846
            self.unversioned(tree2, 'dir'),
 
847
            ]
 
848
        if links_supported:
 
849
            expected.append(self.unversioned(tree2, 'link'))
 
850
        expected = sorted(expected)
 
851
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
852
            want_unversioned=True))
 
853
 
 
854
    def test_unversioned_paths_in_tree_specific_files(self):
 
855
        tree1 = self.make_branch_and_tree('tree1')
 
856
        tree2 = self.make_to_branch_and_tree('tree2')
 
857
        self.build_tree(['tree2/file', 'tree2/dir/'])
 
858
        if has_symlinks():
 
859
            os.symlink('target', 'tree2/link')
 
860
            links_supported = True
 
861
        else:
 
862
            links_supported = False
 
863
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
864
        expected = [
 
865
            self.unversioned(tree2, 'file'),
 
866
            self.unversioned(tree2, 'dir'),
 
867
            ]
 
868
        specific_files=['file', 'dir']
 
869
        if links_supported:
 
870
            expected.append(self.unversioned(tree2, 'link'))
 
871
            specific_files.append('link')
 
872
        expected = sorted(expected)
 
873
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
874
            specific_files=specific_files, require_versioned=False,
 
875
            want_unversioned=True))
 
876
 
 
877
    def test_unversioned_paths_in_target_matching_source_old_names(self):
 
878
        # its likely that naive implementations of unversioned file support
 
879
        # will fail if the path was versioned, but is not any more, 
 
880
        # due to a rename, not due to unversioning it.
 
881
        # That is, if the old tree has a versioned file 'foo', and
 
882
        # the new tree has the same file but versioned as 'bar', and also
 
883
        # has an unknown file 'foo', we should get back output for
 
884
        # both foo and bar.
 
885
        tree1 = self.make_branch_and_tree('tree1')
 
886
        tree2 = self.make_to_branch_and_tree('tree2')
 
887
        tree2.set_root_id(tree1.get_root_id())
 
888
        self.build_tree(['tree2/file', 'tree2/dir/',
 
889
            'tree1/file', 'tree2/movedfile',
 
890
            'tree1/dir/', 'tree2/moveddir/'])
 
891
        if has_symlinks():
 
892
            os.symlink('target', 'tree1/link')
 
893
            os.symlink('target', 'tree2/link')
 
894
            os.symlink('target', 'tree2/movedlink')
 
895
            links_supported = True
 
896
        else:
 
897
            links_supported = False
 
898
        tree1.add(['file', 'dir'], ['file-id', 'dir-id'])
 
899
        tree2.add(['movedfile', 'moveddir'], ['file-id', 'dir-id'])
 
900
        if links_supported:
 
901
            tree1.add(['link'], ['link-id'])
 
902
            tree2.add(['movedlink'], ['link-id'])
 
903
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
904
        root_id = tree1.path2id('')
 
905
        expected = [
 
906
            self.renamed(tree1, tree2, 'dir-id', False),
 
907
            self.renamed(tree1, tree2, 'file-id', True),
 
908
            self.unversioned(tree2, 'file'),
 
909
            self.unversioned(tree2, 'dir'),
 
910
            ]
 
911
        specific_files=['file', 'dir']
 
912
        if links_supported:
 
913
            expected.append(self.renamed(tree1, tree2, 'link-id', False))
 
914
            expected.append(self.unversioned(tree2, 'link'))
 
915
            specific_files.append('link')
 
916
        expected = sorted(expected)
 
917
        # run once with, and once without specific files, to catch
 
918
        # potentially different code paths.
 
919
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
920
            require_versioned=False,
 
921
            want_unversioned=True))
 
922
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
923
            specific_files=specific_files, require_versioned=False,
 
924
            want_unversioned=True))
 
925
 
 
926
    def test_similar_filenames(self):
 
927
        """Test when we have a few files with similar names."""
 
928
        tree1 = self.make_branch_and_tree('tree1')
 
929
        tree2 = self.make_branch_and_tree('tree2')
 
930
        tree2.set_root_id(tree1.get_root_id())
 
931
 
 
932
        # The trees are actually identical, but they happen to contain
 
933
        # similarly named files.
 
934
        self.build_tree(['tree1/a/',
 
935
                         'tree1/a/b/',
 
936
                         'tree1/a/b/c/',
 
937
                         'tree1/a/b/c/d/',
 
938
                         'tree1/a-c/',
 
939
                         'tree1/a-c/e/',
 
940
                         'tree2/a/',
 
941
                         'tree2/a/b/',
 
942
                         'tree2/a/b/c/',
 
943
                         'tree2/a/b/c/d/',
 
944
                         'tree2/a-c/',
 
945
                         'tree2/a-c/e/',
 
946
                        ])
 
947
        tree1.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
 
948
                  ['a-id', 'b-id', 'c-id', 'd-id', 'a-c-id', 'e-id'])
 
949
        tree2.add(['a', 'a/b', 'a/b/c', 'a/b/c/d', 'a-c', 'a-c/e'],
 
950
                  ['a-id', 'b-id', 'c-id', 'd-id', 'a-c-id', 'e-id'])
 
951
 
 
952
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
953
 
 
954
        self.assertEqual([], self.do_iter_changes(tree1, tree2,
 
955
                                                  want_unversioned=True))
 
956
        expected = sorted([
 
957
            self.unchanged(tree2, tree2.get_root_id()),
 
958
            self.unchanged(tree2, 'a-id'),
 
959
            self.unchanged(tree2, 'b-id'),
 
960
            self.unchanged(tree2, 'c-id'),
 
961
            self.unchanged(tree2, 'd-id'),
 
962
            self.unchanged(tree2, 'a-c-id'),
 
963
            self.unchanged(tree2, 'e-id'),
 
964
            ])
 
965
        self.assertEqual(expected,
 
966
                         self.do_iter_changes(tree1, tree2,
 
967
                                              want_unversioned=True,
 
968
                                              include_unchanged=True))
 
969
 
 
970
 
 
971
    def test_unversioned_subtree_only_emits_root(self):
 
972
        tree1 = self.make_branch_and_tree('tree1')
 
973
        tree2 = self.make_to_branch_and_tree('tree2')
 
974
        tree2.set_root_id(tree1.get_root_id())
 
975
        self.build_tree(['tree2/dir/', 'tree2/dir/file'])
 
976
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
 
977
        expected = [
 
978
            self.unversioned(tree2, 'dir'),
 
979
            ]
 
980
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
981
            want_unversioned=True))
 
982
 
 
983
    def make_trees_with_symlinks(self):
 
984
        tree1 = self.make_branch_and_tree('tree1')
 
985
        tree2 = self.make_to_branch_and_tree('tree2')
 
986
        tree2.set_root_id(tree1.get_root_id())
 
987
        self.build_tree(['tree1/fromfile', 'tree1/fromdir/'])
 
988
        self.build_tree(['tree2/tofile', 'tree2/todir/', 'tree2/unknown'])
 
989
        os.symlink('original', 'tree1/changed')
 
990
        os.symlink('original', 'tree1/removed')
 
991
        os.symlink('original', 'tree1/tofile')
 
992
        os.symlink('original', 'tree1/todir')
 
993
        # we make the unchanged link point at unknown to catch incorrect
 
994
        # symlink-following code in the specified_files test.
 
995
        os.symlink('unknown', 'tree1/unchanged')
 
996
        os.symlink('new',      'tree2/added')
 
997
        os.symlink('new',      'tree2/changed')
 
998
        os.symlink('new',      'tree2/fromfile')
 
999
        os.symlink('new',      'tree2/fromdir')
 
1000
        os.symlink('unknown', 'tree2/unchanged')
 
1001
        from_paths_and_ids = [
 
1002
            'fromdir',
 
1003
            'fromfile',
 
1004
            'changed',
 
1005
            'removed',
 
1006
            'todir',
 
1007
            'tofile',
 
1008
            'unchanged',
 
1009
            ]
 
1010
        to_paths_and_ids = [
 
1011
            'added',
 
1012
            'fromdir',
 
1013
            'fromfile',
 
1014
            'changed',
 
1015
            'todir',
 
1016
            'tofile',
 
1017
            'unchanged',
 
1018
            ]
 
1019
        tree1.add(from_paths_and_ids, from_paths_and_ids)
 
1020
        tree2.add(to_paths_and_ids, to_paths_and_ids)
 
1021
        return self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1022
 
 
1023
    def test_versioned_symlinks(self):
 
1024
        self.requireFeature(tests.SymlinkFeature)
 
1025
        tree1, tree2 = self.make_trees_with_symlinks()
 
1026
        root_id = tree1.path2id('')
 
1027
        expected = [
 
1028
            self.unchanged(tree1, tree1.path2id('')),
 
1029
            self.added(tree2, 'added'),
 
1030
            self.content_changed(tree2, 'changed'),
 
1031
            self.kind_changed(tree1, tree2, 'fromdir'),
 
1032
            self.kind_changed(tree1, tree2, 'fromfile'),
 
1033
            self.deleted(tree1, 'removed'),
 
1034
            self.unchanged(tree2, 'unchanged'),
 
1035
            self.unversioned(tree2, 'unknown'),
 
1036
            self.kind_changed(tree1, tree2, 'todir'),
 
1037
            self.kind_changed(tree1, tree2, 'tofile'),
 
1038
            ]
 
1039
        expected = sorted(expected)
 
1040
        self.assertEqual(expected,
 
1041
            self.do_iter_changes(tree1, tree2, include_unchanged=True,
 
1042
                want_unversioned=True))
 
1043
 
 
1044
    def test_versioned_symlinks_specific_files(self):
 
1045
        self.requireFeature(tests.SymlinkFeature)
 
1046
        tree1, tree2 = self.make_trees_with_symlinks()
 
1047
        root_id = tree1.path2id('')
 
1048
        expected = [
 
1049
            self.added(tree2, 'added'),
 
1050
            self.content_changed(tree2, 'changed'),
 
1051
            self.kind_changed(tree1, tree2, 'fromdir'),
 
1052
            self.kind_changed(tree1, tree2, 'fromfile'),
 
1053
            self.deleted(tree1, 'removed'),
 
1054
            self.kind_changed(tree1, tree2, 'todir'),
 
1055
            self.kind_changed(tree1, tree2, 'tofile'),
 
1056
            ]
 
1057
        expected = sorted(expected)
 
1058
        # we should get back just the changed links. We pass in 'unchanged' to
 
1059
        # make sure that it is correctly not returned - and neither is the
 
1060
        # unknown path 'unknown' which it points at.
 
1061
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
 
1062
            specific_files=['added', 'changed', 'fromdir', 'fromfile',
 
1063
            'removed', 'unchanged', 'todir', 'tofile']))
 
1064
 
 
1065
    def test_tree_with_special_names(self):
 
1066
        tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
 
1067
        expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
 
1068
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
1069
 
 
1070
    def test_trees_with_special_names(self):
 
1071
        tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
 
1072
        expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
 
1073
                          if f_id.endswith('_f-id'))
 
1074
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
1075
 
 
1076
    def test_trees_with_deleted_dir(self):
 
1077
        tree1 = self.make_branch_and_tree('tree1')
 
1078
        tree2 = self.make_to_branch_and_tree('tree2')
 
1079
        tree2.set_root_id(tree1.get_root_id())
 
1080
        self.build_tree(['tree1/a', 'tree1/b/', 'tree1/b/c',
 
1081
                         'tree1/b/d/', 'tree1/b/d/e', 'tree1/f/', 'tree1/f/g',
 
1082
                         'tree2/a', 'tree2/f/', 'tree2/f/g'])
 
1083
        tree1.add(['a', 'b', 'b/c', 'b/d/', 'b/d/e', 'f', 'f/g'],
 
1084
                  ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id', 'g-id'])
 
1085
        tree2.add(['a', 'f', 'f/g'], ['a-id', 'f-id', 'g-id'])
 
1086
 
 
1087
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1088
        # We should notice that 'b' and all its children are deleted
 
1089
        expected = sorted([
 
1090
            self.content_changed(tree2, 'a-id'),
 
1091
            self.content_changed(tree2, 'g-id'),
 
1092
            self.deleted(tree1, 'b-id'),
 
1093
            self.deleted(tree1, 'c-id'),
 
1094
            self.deleted(tree1, 'd-id'),
 
1095
            self.deleted(tree1, 'e-id'),
 
1096
            ])
 
1097
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
 
1098
 
 
1099
    def test_added_unicode(self):
 
1100
        tree1 = self.make_branch_and_tree('tree1')
 
1101
        tree2 = self.make_to_branch_and_tree('tree2')
 
1102
        root_id = tree1.get_root_id()
 
1103
        tree2.set_root_id(root_id)
 
1104
 
 
1105
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1106
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1107
        a_id = u'\u03b1-id'.encode('utf8')
 
1108
        added_id = u'\u03c9_added_id'.encode('utf8')
 
1109
        try:
 
1110
            self.build_tree([u'tree1/\u03b1/',
 
1111
                             u'tree2/\u03b1/',
 
1112
                             u'tree2/\u03b1/\u03c9-added',
 
1113
                            ])
 
1114
        except UnicodeError:
 
1115
            raise tests.TestSkipped("Could not create Unicode files.")
 
1116
        tree1.add([u'\u03b1'], [a_id])
 
1117
        tree2.add([u'\u03b1', u'\u03b1/\u03c9-added'], [a_id, added_id])
 
1118
 
 
1119
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1120
 
 
1121
        self.assertEqual([self.added(tree2, added_id)],
 
1122
                         self.do_iter_changes(tree1, tree2))
 
1123
        self.assertEqual([self.added(tree2, added_id)],
 
1124
                         self.do_iter_changes(tree1, tree2,
 
1125
                                              specific_files=[u'\u03b1']))
 
1126
 
 
1127
    def test_deleted_unicode(self):
 
1128
        tree1 = self.make_branch_and_tree('tree1')
 
1129
        tree2 = self.make_to_branch_and_tree('tree2')
 
1130
        root_id = tree1.get_root_id()
 
1131
        tree2.set_root_id(root_id)
 
1132
 
 
1133
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1134
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1135
        a_id = u'\u03b1-id'.encode('utf8')
 
1136
        deleted_id = u'\u03c9_deleted_id'.encode('utf8')
 
1137
        try:
 
1138
            self.build_tree([u'tree1/\u03b1/',
 
1139
                             u'tree1/\u03b1/\u03c9-deleted',
 
1140
                             u'tree2/\u03b1/',
 
1141
                            ])
 
1142
        except UnicodeError:
 
1143
            raise tests.TestSkipped("Could not create Unicode files.")
 
1144
        tree1.add([u'\u03b1', u'\u03b1/\u03c9-deleted'], [a_id, deleted_id])
 
1145
        tree2.add([u'\u03b1'], [a_id])
 
1146
 
 
1147
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1148
 
 
1149
        self.assertEqual([self.deleted(tree1, deleted_id)],
 
1150
                         self.do_iter_changes(tree1, tree2))
 
1151
        self.assertEqual([self.deleted(tree1, deleted_id)],
 
1152
                         self.do_iter_changes(tree1, tree2,
 
1153
                                              specific_files=[u'\u03b1']))
 
1154
 
 
1155
    def test_modified_unicode(self):
 
1156
        tree1 = self.make_branch_and_tree('tree1')
 
1157
        tree2 = self.make_to_branch_and_tree('tree2')
 
1158
        root_id = tree1.get_root_id()
 
1159
        tree2.set_root_id(root_id)
 
1160
 
 
1161
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1162
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1163
        a_id = u'\u03b1-id'.encode('utf8')
 
1164
        mod_id = u'\u03c9_mod_id'.encode('utf8')
 
1165
        try:
 
1166
            self.build_tree([u'tree1/\u03b1/',
 
1167
                             u'tree1/\u03b1/\u03c9-modified',
 
1168
                             u'tree2/\u03b1/',
 
1169
                             u'tree2/\u03b1/\u03c9-modified',
 
1170
                            ])
 
1171
        except UnicodeError:
 
1172
            raise tests.TestSkipped("Could not create Unicode files.")
 
1173
        tree1.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
 
1174
        tree2.add([u'\u03b1', u'\u03b1/\u03c9-modified'], [a_id, mod_id])
 
1175
 
 
1176
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1177
 
 
1178
        self.assertEqual([self.content_changed(tree1, mod_id)],
 
1179
                         self.do_iter_changes(tree1, tree2))
 
1180
        self.assertEqual([self.content_changed(tree1, mod_id)],
 
1181
                         self.do_iter_changes(tree1, tree2,
 
1182
                                              specific_files=[u'\u03b1']))
 
1183
 
 
1184
    def test_renamed_unicode(self):
 
1185
        tree1 = self.make_branch_and_tree('tree1')
 
1186
        tree2 = self.make_to_branch_and_tree('tree2')
 
1187
        root_id = tree1.get_root_id()
 
1188
        tree2.set_root_id(root_id)
 
1189
 
 
1190
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1191
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1192
        a_id = u'\u03b1-id'.encode('utf8')
 
1193
        rename_id = u'\u03c9_rename_id'.encode('utf8')
 
1194
        try:
 
1195
            self.build_tree([u'tree1/\u03b1/',
 
1196
                             u'tree2/\u03b1/',
 
1197
                            ])
 
1198
        except UnicodeError:
 
1199
            raise tests.TestSkipped("Could not create Unicode files.")
 
1200
        self.build_tree_contents([(u'tree1/\u03c9-source', 'contents\n'),
 
1201
                                  (u'tree2/\u03b1/\u03c9-target', 'contents\n'),
 
1202
                                 ])
 
1203
        tree1.add([u'\u03b1', u'\u03c9-source'], [a_id, rename_id])
 
1204
        tree2.add([u'\u03b1', u'\u03b1/\u03c9-target'], [a_id, rename_id])
 
1205
 
 
1206
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1207
 
 
1208
        self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
 
1209
                         self.do_iter_changes(tree1, tree2))
 
1210
        self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
 
1211
                         self.do_iter_changes(tree1, tree2,
 
1212
                                              specific_files=[u'\u03b1']))
 
1213
 
 
1214
    def test_unchanged_unicode(self):
 
1215
        tree1 = self.make_branch_and_tree('tree1')
 
1216
        tree2 = self.make_to_branch_and_tree('tree2')
 
1217
        root_id = tree1.get_root_id()
 
1218
        tree2.set_root_id(root_id)
 
1219
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1220
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1221
        a_id = u'\u03b1-id'.encode('utf8')
 
1222
        subfile_id = u'\u03c9-subfile-id'.encode('utf8')
 
1223
        rootfile_id = u'\u03c9-root-id'.encode('utf8')
 
1224
        try:
 
1225
            self.build_tree([u'tree1/\u03b1/',
 
1226
                             u'tree2/\u03b1/',
 
1227
                            ])
 
1228
        except UnicodeError:
 
1229
            raise tests.TestSkipped("Could not create Unicode files.")
 
1230
        self.build_tree_contents([
 
1231
            (u'tree1/\u03b1/\u03c9-subfile', 'sub contents\n'),
 
1232
            (u'tree2/\u03b1/\u03c9-subfile', 'sub contents\n'),
 
1233
            (u'tree1/\u03c9-rootfile', 'root contents\n'),
 
1234
            (u'tree2/\u03c9-rootfile', 'root contents\n'),
 
1235
            ])
 
1236
        tree1.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
 
1237
                  [a_id, subfile_id, rootfile_id])
 
1238
        tree2.add([u'\u03b1', u'\u03b1/\u03c9-subfile', u'\u03c9-rootfile'],
 
1239
                  [a_id, subfile_id, rootfile_id])
 
1240
 
 
1241
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1242
 
 
1243
        expected = sorted([
 
1244
            self.unchanged(tree1, root_id),
 
1245
            self.unchanged(tree1, a_id),
 
1246
            self.unchanged(tree1, subfile_id),
 
1247
            self.unchanged(tree1, rootfile_id),
 
1248
            ])
 
1249
        self.assertEqual(expected,
 
1250
                         self.do_iter_changes(tree1, tree2,
 
1251
                                              include_unchanged=True))
 
1252
 
 
1253
        # We should also be able to select just a subset
 
1254
        expected = sorted([
 
1255
            self.unchanged(tree1, a_id),
 
1256
            self.unchanged(tree1, subfile_id),
 
1257
            ])
 
1258
        self.assertEqual(expected,
 
1259
                         self.do_iter_changes(tree1, tree2,
 
1260
                                              specific_files=[u'\u03b1'],
 
1261
                                              include_unchanged=True))
 
1262
 
 
1263
    def test_unknown_unicode(self):
 
1264
        tree1 = self.make_branch_and_tree('tree1')
 
1265
        tree2 = self.make_to_branch_and_tree('tree2')
 
1266
        root_id = tree1.get_root_id()
 
1267
        tree2.set_root_id(root_id)
 
1268
        # u'\u03b1' == GREEK SMALL LETTER ALPHA
 
1269
        # u'\u03c9' == GREEK SMALL LETTER OMEGA
 
1270
        a_id = u'\u03b1-id'.encode('utf8')
 
1271
        try:
 
1272
            self.build_tree([u'tree1/\u03b1/',
 
1273
                             u'tree2/\u03b1/',
 
1274
                             u'tree2/\u03b1/unknown_dir/',
 
1275
                             u'tree2/\u03b1/unknown_file',
 
1276
                             u'tree2/\u03b1/unknown_dir/file',
 
1277
                             u'tree2/\u03c9-unknown_root_file',
 
1278
                            ])
 
1279
        except UnicodeError:
 
1280
            raise tests.TestSkipped("Could not create Unicode files.")
 
1281
        tree1.add([u'\u03b1'], [a_id])
 
1282
        tree2.add([u'\u03b1'], [a_id])
 
1283
 
 
1284
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1285
 
 
1286
        expected = sorted([
 
1287
            self.unversioned(tree2, u'\u03b1/unknown_dir'),
 
1288
            self.unversioned(tree2, u'\u03b1/unknown_file'),
 
1289
            self.unversioned(tree2, u'\u03c9-unknown_root_file'),
 
1290
            # a/unknown_dir/file should not be included because we should not
 
1291
            # recurse into unknown_dir
 
1292
            # self.unversioned(tree2, 'a/unknown_dir/file'),
 
1293
            ])
 
1294
        self.assertEqual(expected,
 
1295
                         self.do_iter_changes(tree1, tree2,
 
1296
                                              require_versioned=False,
 
1297
                                              want_unversioned=True))
 
1298
        self.assertEqual([], # Without want_unversioned we should get nothing
 
1299
                         self.do_iter_changes(tree1, tree2))
 
1300
 
 
1301
        # We should also be able to select just a subset
 
1302
        expected = sorted([
 
1303
            self.unversioned(tree2, u'\u03b1/unknown_dir'),
 
1304
            self.unversioned(tree2, u'\u03b1/unknown_file'),
 
1305
            ])
 
1306
        self.assertEqual(expected,
 
1307
                         self.do_iter_changes(tree1, tree2,
 
1308
                                              specific_files=[u'\u03b1'],
 
1309
                                              require_versioned=False,
 
1310
                                              want_unversioned=True))
 
1311
        self.assertEqual([], # Without want_unversioned we should get nothing
 
1312
                         self.do_iter_changes(tree1, tree2,
 
1313
                                              specific_files=[u'\u03b1']))
 
1314
 
 
1315
    def test_unknown_empty_dir(self):
 
1316
        tree1 = self.make_branch_and_tree('tree1')
 
1317
        tree2 = self.make_to_branch_and_tree('tree2')
 
1318
        root_id = tree1.get_root_id()
 
1319
        tree2.set_root_id(root_id)
 
1320
 
 
1321
        # Start with 2 identical trees
 
1322
        self.build_tree(['tree1/a/', 'tree1/b/',
 
1323
                         'tree2/a/', 'tree2/b/'])
 
1324
        self.build_tree_contents([('tree1/b/file', 'contents\n'),
 
1325
                                  ('tree2/b/file', 'contents\n')])
 
1326
        tree1.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
 
1327
        tree2.add(['a', 'b', 'b/file'], ['a-id', 'b-id', 'b-file-id'])
 
1328
 
 
1329
        # Now create some unknowns in tree2
 
1330
        # We should find both a/file and a/dir as unknown, but we shouldn't
 
1331
        # recurse into a/dir to find that a/dir/subfile is also unknown.
 
1332
        self.build_tree(['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
 
1333
 
 
1334
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1335
 
 
1336
        expected = sorted([
 
1337
            self.unversioned(tree2, u'a/file'),
 
1338
            self.unversioned(tree2, u'a/dir'),
 
1339
            ])
 
1340
        self.assertEqual(expected,
 
1341
                         self.do_iter_changes(tree1, tree2,
 
1342
                                              require_versioned=False,
 
1343
                                              want_unversioned=True))
 
1344
 
 
1345
    def test_rename_over_deleted(self):
 
1346
        tree1 = self.make_branch_and_tree('tree1')
 
1347
        tree2 = self.make_to_branch_and_tree('tree2')
 
1348
        root_id = tree1.get_root_id()
 
1349
        tree2.set_root_id(root_id)
 
1350
 
 
1351
        # The final changes should be:
 
1352
        #   touch a b c d
 
1353
        #   add a b c d
 
1354
        #   commit
 
1355
        #   rm a d
 
1356
        #   mv b a
 
1357
        #   mv c d
 
1358
        self.build_tree_contents([
 
1359
            ('tree1/a', 'a contents\n'),
 
1360
            ('tree1/b', 'b contents\n'),
 
1361
            ('tree1/c', 'c contents\n'),
 
1362
            ('tree1/d', 'd contents\n'),
 
1363
            ('tree2/a', 'b contents\n'),
 
1364
            ('tree2/d', 'c contents\n'),
 
1365
            ])
 
1366
        tree1.add(['a', 'b', 'c', 'd'], ['a-id', 'b-id', 'c-id', 'd-id'])
 
1367
        tree2.add(['a', 'd'], ['b-id', 'c-id'])
 
1368
 
 
1369
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1370
 
 
1371
        expected = sorted([
 
1372
            self.deleted(tree1, 'a-id'),
 
1373
            self.deleted(tree1, 'd-id'),
 
1374
            self.renamed(tree1, tree2, 'b-id', False),
 
1375
            self.renamed(tree1, tree2, 'c-id', False),
 
1376
            ])
 
1377
        self.assertEqual(expected,
 
1378
                         self.do_iter_changes(tree1, tree2))
 
1379
 
 
1380
    def test_deleted_and_unknown(self):
 
1381
        """Test a file marked removed, but still present on disk."""
 
1382
        tree1 = self.make_branch_and_tree('tree1')
 
1383
        tree2 = self.make_to_branch_and_tree('tree2')
 
1384
        root_id = tree1.get_root_id()
 
1385
        tree2.set_root_id(root_id)
 
1386
 
 
1387
        # The final changes should be:
 
1388
        # bzr add a b c
 
1389
        # bzr rm --keep b
 
1390
        self.build_tree_contents([
 
1391
            ('tree1/a', 'a contents\n'),
 
1392
            ('tree1/b', 'b contents\n'),
 
1393
            ('tree1/c', 'c contents\n'),
 
1394
            ('tree2/a', 'a contents\n'),
 
1395
            ('tree2/b', 'b contents\n'),
 
1396
            ('tree2/c', 'c contents\n'),
 
1397
            ])
 
1398
        tree1.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
 
1399
        tree2.add(['a', 'c'], ['a-id', 'c-id'])
 
1400
 
 
1401
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1402
 
 
1403
        expected = sorted([
 
1404
            self.deleted(tree1, 'b-id'),
 
1405
            self.unversioned(tree2, 'b'),
 
1406
            ])
 
1407
        self.assertEqual(expected,
 
1408
                         self.do_iter_changes(tree1, tree2,
 
1409
                                              want_unversioned=True))
 
1410
        expected = sorted([
 
1411
            self.deleted(tree1, 'b-id'),
 
1412
            ])
 
1413
        self.assertEqual(expected,
 
1414
                         self.do_iter_changes(tree1, tree2,
 
1415
                                              want_unversioned=False))
 
1416
 
 
1417
    def test_renamed_and_added(self):
 
1418
        """Test when we have renamed a file, and put another in its place."""
 
1419
        tree1 = self.make_branch_and_tree('tree1')
 
1420
        tree2 = self.make_to_branch_and_tree('tree2')
 
1421
        root_id = tree1.get_root_id()
 
1422
        tree2.set_root_id(root_id)
 
1423
 
 
1424
        # The final changes are:
 
1425
        # bzr add b c
 
1426
        # bzr mv b a
 
1427
        # bzr mv c d
 
1428
        # bzr add b c
 
1429
 
 
1430
        self.build_tree_contents([
 
1431
            ('tree1/b', 'b contents\n'),
 
1432
            ('tree1/c', 'c contents\n'),
 
1433
            ('tree2/a', 'b contents\n'),
 
1434
            ('tree2/b', 'new b contents\n'),
 
1435
            ('tree2/c', 'new c contents\n'),
 
1436
            ('tree2/d', 'c contents\n'),
 
1437
            ])
 
1438
        tree1.add(['b', 'c'], ['b1-id', 'c1-id'])
 
1439
        tree2.add(['a', 'b', 'c', 'd'], ['b1-id', 'b2-id', 'c2-id', 'c1-id'])
 
1440
 
 
1441
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1442
 
 
1443
        expected = sorted([
 
1444
            self.renamed(tree1, tree2, 'b1-id', False),
 
1445
            self.renamed(tree1, tree2, 'c1-id', False),
 
1446
            self.added(tree2, 'b2-id'),
 
1447
            self.added(tree2, 'c2-id'),
 
1448
            ])
 
1449
        self.assertEqual(expected,
 
1450
                         self.do_iter_changes(tree1, tree2,
 
1451
                                              want_unversioned=True))
 
1452
 
 
1453
    def test_renamed_and_unknown(self):
 
1454
        """A file was moved on the filesystem, but not in bzr."""
 
1455
        tree1 = self.make_branch_and_tree('tree1')
 
1456
        tree2 = self.make_to_branch_and_tree('tree2')
 
1457
        root_id = tree1.get_root_id()
 
1458
        tree2.set_root_id(root_id)
 
1459
 
 
1460
        # The final changes are:
 
1461
        # bzr add a b
 
1462
        # mv a a2
 
1463
 
 
1464
        self.build_tree_contents([
 
1465
            ('tree1/a', 'a contents\n'),
 
1466
            ('tree1/b', 'b contents\n'),
 
1467
            ('tree2/a', 'a contents\n'),
 
1468
            ('tree2/b', 'b contents\n'),
 
1469
            ])
 
1470
        tree1.add(['a', 'b'], ['a-id', 'b-id'])
 
1471
        tree2.add(['a', 'b'], ['a-id', 'b-id'])
 
1472
        os.rename('tree2/a', 'tree2/a2')
 
1473
 
 
1474
        tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
 
1475
 
 
1476
        expected = sorted([
 
1477
            self.missing('a-id', 'a', 'a', tree2.get_root_id(), 'file'),
 
1478
            self.unversioned(tree2, 'a2'),
 
1479
            ])
 
1480
        self.assertEqual(expected,
 
1481
                         self.do_iter_changes(tree1, tree2,
 
1482
                                              want_unversioned=True))