/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.152 by Martin Pool
(broken) merge aaron's workingtree format changes
1
# Copyright (C) 2006, 2007 Canonical Ltd
1852.8.3 by Robert Collins
Implement an InterTreeTestProvider and a trivial test_compare test case.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for the InterTree.compare() function."""
18
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
19
import os
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
20
import shutil
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
21
2255.6.4 by Aaron Bentley
merge from dirstate
22
from bzrlib import errors, tests, workingtree_4
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
23
from bzrlib.osutils import file_kind
1852.8.3 by Robert Collins
Implement an InterTreeTestProvider and a trivial test_compare test case.
24
from bzrlib.tests.intertree_implementations import TestCaseWithTwoTrees
25
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
26
# TODO: test diff unversioned dir that exists
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: include dangling in the diff output.
34
# TODO: test items are only emitted once when a specific_files list names a dir
35
#       whose parent is now a child.
36
# TODO: test require_versioned
2255.2.151 by Robert Collins
Handle specific_files natively for WorkingTreeFormat4._iter_changes.
37
# TODO: explicitly test specific_files listing a non-dir, and listing a symlink
38
#       (it should not follow the link)
39
# TODO: test specific_files when the target tree has a file and the source a
40
#       dir with children, same id and same path. 
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
41
# TODO: test comparisons between trees with different root ids. mbp 20070301
1852.8.3 by Robert Collins
Implement an InterTreeTestProvider and a trivial test_compare test case.
42
43
class TestCompare(TestCaseWithTwoTrees):
44
45
    def test_compare_empty_trees(self):
46
        tree1 = self.make_branch_and_tree('1')
47
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
48
        tree2.set_root_id(tree1.get_root_id())
1852.8.3 by Robert Collins
Implement an InterTreeTestProvider and a trivial test_compare test case.
49
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
50
        tree2 = self.get_tree_no_parents_no_content(tree2)
51
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.8.3 by Robert Collins
Implement an InterTreeTestProvider and a trivial test_compare test case.
52
        d = self.intertree_class(tree1, tree2).compare()
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
53
        self.assertEqual([], d.added)
54
        self.assertEqual([], d.modified)
55
        self.assertEqual([], d.removed)
56
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
57
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
58
59
    def test_empty_to_abc_content(self):
60
        tree1 = self.make_branch_and_tree('1')
61
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
62
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
63
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
64
        tree2 = self.get_tree_no_parents_abc_content(tree2)
65
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
66
        d = self.intertree_class(tree1, tree2).compare()
67
        self.assertEqual([('a', 'a-id', 'file'),
68
                          ('b', 'b-id', 'directory'),
69
                          ('b/c', 'c-id', 'file'),
70
                         ], d.added)
71
        self.assertEqual([], d.modified)
72
        self.assertEqual([], d.removed)
73
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
74
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
75
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
76
    def test_dangling(self):
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
77
        # This test depends on the ability for some trees to have a difference
78
        # between a 'versioned present' and 'versioned not present' (aka
79
        # dangling) file. In this test there are two trees each with a separate
80
        # dangling file, and the dangling files should be considered absent for
81
        # the test.
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
82
        tree1 = self.make_branch_and_tree('1')
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
83
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
84
        tree2.set_root_id(tree1.get_root_id())
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
85
        self.build_tree(['2/a'])
86
        tree2.add('a')
87
        os.unlink('2/a')
88
        self.build_tree(['1/b'])
89
        tree1.add('b')
90
        os.unlink('1/b')
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
91
        # the conversion to test trees here will leave the trees intact for the
92
        # default intertree, but may perform a commit for other tree types,
93
        # which may reduce the validity of the test. XXX: Think about how to
94
        # address this.
95
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
96
        d = self.intertree_class(tree1, tree2).compare()
97
        self.assertEqual([], d.added)
98
        self.assertEqual([], d.modified)
99
        self.assertEqual([], d.removed)
100
        self.assertEqual([], d.renamed)
101
        self.assertEqual([], d.unchanged)
102
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
103
    def test_abc_content_to_empty(self):
104
        tree1 = self.make_branch_and_tree('1')
105
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
106
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
107
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
108
        tree2 = self.get_tree_no_parents_no_content(tree2)
109
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
110
        d = self.intertree_class(tree1, tree2).compare()
111
        self.assertEqual([], d.added)
112
        self.assertEqual([], d.modified)
113
        self.assertEqual([('a', 'a-id', 'file'),
114
                          ('b', 'b-id', 'directory'),
115
                          ('b/c', 'c-id', 'file'),
116
                         ], d.removed)
117
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
118
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
119
120
    def test_content_modification(self):
121
        tree1 = self.make_branch_and_tree('1')
122
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
123
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
124
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
125
        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
126
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
127
        d = self.intertree_class(tree1, tree2).compare()
128
        self.assertEqual([], d.added)
129
        self.assertEqual([('a', 'a-id', 'file', True, False)], d.modified)
130
        self.assertEqual([], d.removed)
131
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
132
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
133
        
134
    def test_meta_modification(self):
135
        tree1 = self.make_branch_and_tree('1')
136
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
137
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
138
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
139
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
140
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
141
        d = self.intertree_class(tree1, tree2).compare()
142
        self.assertEqual([], d.added)
143
        self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
144
        self.assertEqual([], d.removed)
145
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
146
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
147
148
    def test_file_rename(self):
149
        tree1 = self.make_branch_and_tree('1')
150
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
151
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
152
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
153
        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
154
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
155
        d = self.intertree_class(tree1, tree2).compare()
156
        self.assertEqual([], d.added)
157
        self.assertEqual([], d.modified)
158
        self.assertEqual([], d.removed)
159
        self.assertEqual([('a', 'd', 'a-id', 'file', False, False)], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
160
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
161
162
    def test_file_rename_and_modification(self):
163
        tree1 = self.make_branch_and_tree('1')
164
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
165
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
166
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
167
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
168
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
169
        d = self.intertree_class(tree1, tree2).compare()
170
        self.assertEqual([], d.added)
171
        self.assertEqual([], d.modified)
172
        self.assertEqual([], d.removed)
173
        self.assertEqual([('a', 'd', 'a-id', 'file', True, False)], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
174
        self.assertEqual([], d.unchanged)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
175
176
    def test_file_rename_and_meta_modification(self):
177
        tree1 = self.make_branch_and_tree('1')
178
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
179
        tree2.set_root_id(tree1.get_root_id())
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
180
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
181
        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
182
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.2 by Robert Collins
Convert stock delta tests to intertree_implementation tests of InterTree.compare.
183
        d = self.intertree_class(tree1, tree2).compare()
184
        self.assertEqual([], d.added)
185
        self.assertEqual([], d.modified)
186
        self.assertEqual([], d.removed)
187
        self.assertEqual([('b/c', 'e', 'c-id', 'file', False, True)], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
188
        self.assertEqual([], d.unchanged)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
189
190
    def test_empty_to_abc_content_a_only(self):
191
        tree1 = self.make_branch_and_tree('1')
192
        tree2 = self.make_to_branch_and_tree('2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
193
        tree2.set_root_id(tree1.get_root_id())
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
194
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
195
        tree2 = self.get_tree_no_parents_abc_content(tree2)
196
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
197
        d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
198
        self.assertEqual([('a', 'a-id', 'file')], d.added)
199
        self.assertEqual([], d.modified)
200
        self.assertEqual([], d.removed)
201
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
202
        self.assertEqual([], d.unchanged)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
203
204
    def test_empty_to_abc_content_a_and_c_only(self):
205
        tree1 = self.make_branch_and_tree('1')
206
        tree2 = self.make_to_branch_and_tree('2')
207
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
208
        tree2 = self.get_tree_no_parents_abc_content(tree2)
209
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
210
        d = self.intertree_class(tree1, tree2).compare(
211
            specific_files=['a', 'b/c'])
212
        self.assertEqual(
213
            [('a', 'a-id', 'file'), ('b/c', 'c-id', 'file')],
214
            d.added)
215
        self.assertEqual([], d.modified)
216
        self.assertEqual([], d.removed)
217
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
218
        self.assertEqual([], d.unchanged)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
219
220
    def test_empty_to_abc_content_b_only(self):
221
        """Restricting to a dir matches the children of the dir."""
222
        tree1 = self.make_branch_and_tree('1')
223
        tree2 = self.make_to_branch_and_tree('2')
224
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
225
        tree2 = self.get_tree_no_parents_abc_content(tree2)
226
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
227
        d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
228
        self.assertEqual(
229
            [('b', 'b-id', 'directory'),('b/c', 'c-id', 'file')],
230
            d.added)
231
        self.assertEqual([], d.modified)
232
        self.assertEqual([], d.removed)
233
        self.assertEqual([], d.renamed)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
234
        self.assertEqual([], d.unchanged)
235
236
    def test_unchanged_with_renames_and_modifications(self):
237
        """want_unchanged should generate a list of unchanged entries."""
238
        tree1 = self.make_branch_and_tree('1')
239
        tree2 = self.make_to_branch_and_tree('2')
240
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
241
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
242
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
243
        d = self.intertree_class(tree1, tree2).compare(want_unchanged=True)
244
        self.assertEqual([], d.added)
245
        self.assertEqual([], d.modified)
246
        self.assertEqual([], d.removed)
247
        self.assertEqual([('a', 'd', 'a-id', 'file', True, False)], d.renamed)
248
        self.assertEqual(
249
            [(u'b', 'b-id', 'directory'), (u'b/c', 'c-id', 'file')],
250
            d.unchanged)
251
252
    def test_extra_trees_finds_ids(self):
253
        """Ask for a delta between two trees with a path present in a third."""
254
        tree1 = self.make_branch_and_tree('1')
255
        tree2 = self.make_to_branch_and_tree('2')
256
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
257
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
258
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
259
        d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
260
        # the type of tree-3 does not matter - it is used as a lookup, not
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
261
        # a dispatch. XXX: For dirstate it does speak to the optimisability of
262
        # the lookup, in merged trees it can be fast-pathed. We probably want
263
        # two tests: one as is, and one with it as a pending merge.
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
264
        tree3 = self.make_branch_and_tree('3')
265
        tree3 = self.get_tree_no_parents_abc_content_6(tree3)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
266
        tree3.lock_read()
267
        self.addCleanup(tree3.unlock)
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
268
        # tree 3 has 'e' which is 'c-id'. Tree 1 has c-id at b/c, and Tree 2
269
        # has c-id at b/c with its exec flag toggled.
270
        # without extra_trees, we should get no modifications from this
271
        # so do one, to be sure the test is valid.
272
        d = self.intertree_class(tree1, tree2).compare(
273
            specific_files=['e'])
274
        self.assertEqual([], d.modified)
275
        # now give it an additional lookup:
276
        d = self.intertree_class(tree1, tree2).compare(
277
            specific_files=['e'], extra_trees=[tree3])
278
        self.assertEqual([], d.added)
279
        self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
280
        self.assertEqual([], d.removed)
281
        self.assertEqual([], d.renamed)
282
        self.assertEqual([], d.unchanged)
1852.9.5 by Robert Collins
Add tests for require_versioned to the InterTree.compare() test suite.
283
284
    def test_require_versioned(self):
285
        # this does not quite robustly test, as it is passing in missing paths
286
        # rather than present-but-not-versioned paths. At the moment there is
287
        # no mechanism for managing the test trees (which are readonly) to 
288
        # get present-but-not-versioned files for trees that can do that.
289
        tree1 = self.make_branch_and_tree('1')
290
        tree2 = self.make_to_branch_and_tree('2')
291
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
292
        tree2 = self.get_tree_no_parents_abc_content(tree2)
293
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1852.9.5 by Robert Collins
Add tests for require_versioned to the InterTree.compare() test suite.
294
        self.assertRaises(errors.PathsNotVersionedError, 
295
            self.intertree_class(tree1, tree2).compare,
296
            specific_files=['d'],
297
            require_versioned=True)
2012.1.1 by Aaron Bentley
Implement change iterator
298
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
299
    def test_default_ignores_unversioned_files(self):
300
        tree1 = self.make_branch_and_tree('tree1')
301
        tree2 = self.make_to_branch_and_tree('tree2')
302
        self.build_tree(['tree1/a', 'tree1/c',
303
                         'tree2/a', 'tree2/b', 'tree2/c'])
304
        tree1.add(['a', 'c'], ['a-id', 'c-id'])
305
        tree2.add(['a', 'c'], ['a-id', 'c-id'])
306
307
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2255.7.91 by Robert Collins
Move unknown detection in long status into the delta creation, saving a tree-scan.
308
        d = self.intertree_class(tree1, tree2).compare()
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
309
        self.assertEqual([], d.added)
310
        self.assertEqual([(u'a', 'a-id', 'file', True, False),
311
            (u'c', 'c-id', 'file', True, False)], d.modified)
312
        self.assertEqual([], d.removed)
313
        self.assertEqual([], d.renamed)
314
        self.assertEqual([], d.unchanged)
315
        self.assertEqual([], d.unversioned)
316
317
    def test_unversioned_paths_in_tree(self):
318
        tree1 = self.make_branch_and_tree('tree1')
319
        tree2 = self.make_to_branch_and_tree('tree2')
320
        self.build_tree(['tree2/file', 'tree2/dir/'])
321
        # try:
322
        os.symlink('target', 'tree2/link')
323
        links_supported = True
324
        # except ???:
325
        #   links_supported = False
326
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
327
        d = self.intertree_class(tree1, tree2).compare(want_unversioned=True)
328
        self.assertEqual([], d.added)
329
        self.assertEqual([], d.modified)
330
        self.assertEqual([], d.removed)
331
        self.assertEqual([], d.renamed)
332
        self.assertEqual([], d.unchanged)
2255.7.91 by Robert Collins
Move unknown detection in long status into the delta creation, saving a tree-scan.
333
        self.assertEqual([(u'dir', None, 'directory'), (u'file', None, 'file'),
334
            (u'link', None, 'symlink')], d.unversioned)
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
335
2012.1.1 by Aaron Bentley
Implement change iterator
336
2012.1.3 by Aaron Bentley
Always generate tuples (because kind is always used, even when not different)
337
class TestIterChanges(TestCaseWithTwoTrees):
2012.1.1 by Aaron Bentley
Implement change iterator
338
    """Test the comparison iterator"""
339
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
340
    def do_iter_changes(self, tree1, tree2, **extra_args):
341
        """Helper to run _iter_changes from tree1 to tree2.
342
        
343
        :param tree1, tree2:  The source and target trees. These will be locked
344
            automatically.
345
        :param **extra_args: Extra args to pass to _iter_changes. This is not
346
            inspected by this test helper.
347
        """
348
        tree1.lock_read()
349
        tree2.lock_read()
350
        try:
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
351
            # sort order of output is not strictly defined
352
            return sorted(self.intertree_class(tree1, tree2)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
353
                ._iter_changes(**extra_args))
354
        finally:
355
            tree1.unlock()
356
            tree2.unlock()
357
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
358
    def make_tree_with_special_names(self):
359
        """Create a tree with filenames chosen to exercise the walk order."""
360
        tree1 = self.make_branch_and_tree('tree1')
361
        tree2 = self.make_to_branch_and_tree('tree2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
362
        tree2.set_root_id(tree1.get_root_id())
2255.7.22 by John Arbash Meinel
add a test that shows _iter_changes works when only contents have changed, and nothing is considered newly added.
363
        paths, path_ids = self._create_special_names(tree2, 'tree2')
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
364
        tree2.commit('initial', rev_id='rev-1')
365
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2255.7.22 by John Arbash Meinel
add a test that shows _iter_changes works when only contents have changed, and nothing is considered newly added.
366
        return (tree1, tree2, paths, path_ids)
367
368
    def make_trees_with_special_names(self):
369
        """Both trees will use the special names.
370
371
        But the contents will differ for each file.
372
        """
373
        tree1 = self.make_branch_and_tree('tree1')
374
        tree2 = self.make_to_branch_and_tree('tree2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
375
        tree2.set_root_id(tree1.get_root_id())
2255.7.22 by John Arbash Meinel
add a test that shows _iter_changes works when only contents have changed, and nothing is considered newly added.
376
        paths, path_ids = self._create_special_names(tree1, 'tree1')
377
        paths, path_ids = self._create_special_names(tree2, 'tree2')
378
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
379
        return (tree1, tree2, paths, path_ids)
380
381
    def _create_special_names(self, tree, base_path):
382
        """Create a tree with paths that expose differences in sort orders."""
383
        # Each directory will have a single file named 'f' inside
384
        dirs = ['a',
385
                'a-a',
386
                'a/a',
387
                'a/a-a',
388
                'a/a/a',
389
                'a/a/a-a',
390
                'a/a/a/a',
391
                'a/a/a/a-a',
392
                'a/a/a/a/a',
393
               ]
394
        with_slashes = []
395
        paths = []
396
        path_ids = []
397
        for d in dirs:
398
            with_slashes.append(base_path + '/' + d + '/')
399
            with_slashes.append(base_path + '/' + d + '/f')
400
            paths.append(d)
401
            paths.append(d+'/f')
402
            path_ids.append(d.replace('/', '_') + '-id')
403
            path_ids.append(d.replace('/', '_') + '_f-id')
404
        self.build_tree(with_slashes)
405
        tree.add(paths, path_ids)
406
        return paths, path_ids
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
407
2012.1.1 by Aaron Bentley
Implement change iterator
408
    def test_compare_empty_trees(self):
409
        tree1 = self.make_branch_and_tree('1')
410
        tree2 = self.make_to_branch_and_tree('2')
411
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
412
        tree2 = self.get_tree_no_parents_no_content(tree2)
413
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
414
        self.assertEqual([], self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
415
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
416
    def added(self, tree, file_id):
417
        entry = tree.inventory[file_id]
418
        path = tree.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
419
        return (file_id, (None, path), True, (False, True), (None, entry.parent_id),
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
420
                (None, entry.name), (None, entry.kind),
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
421
                (None, entry.executable))
422
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
423
    def content_changed(self, tree, file_id):
424
        entry = tree.inventory[file_id]
425
        path = tree.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
426
        return (file_id, (path, path), True, (True, True), (entry.parent_id, entry.parent_id),
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
427
                (entry.name, entry.name), (entry.kind, entry.kind),
428
                (entry.executable, entry.executable))
429
430
    def kind_changed(self, from_tree, to_tree, file_id):
431
        old_entry = from_tree.inventory[file_id]
432
        new_entry = to_tree.inventory[file_id]
433
        path = to_tree.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
434
        from_path = from_tree.id2path(file_id)
435
        return (file_id, (from_path, path), True, (True, True), (old_entry.parent_id, new_entry.parent_id),
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
436
                (old_entry.name, new_entry.name), (old_entry.kind, new_entry.kind),
437
                (old_entry.executable, new_entry.executable))
438
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
439
    def missing(self, file_id, from_path, to_path, parent_id, kind):
440
        _, from_basename = os.path.split(from_path)
441
        _, to_basename = os.path.split(to_path)
442
        # missing files have both paths, but no kind.
443
        return (file_id, (from_path, to_path), True, (True, True),
444
            (parent_id, parent_id),
445
            (from_basename, to_basename), (kind, None), (False, False))
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
446
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
447
    def deleted(self, tree, file_id):
448
        entry = tree.inventory[file_id]
449
        path = tree.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
450
        return (file_id, (path, None), True, (True, False), (entry.parent_id, None),
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
451
                (entry.name, None), (entry.kind, None),
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
452
                (entry.executable, None))
453
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
454
    def renamed(self, from_tree, to_tree, file_id, content_changed):
455
        from_entry = from_tree.inventory[file_id]
456
        to_entry = to_tree.inventory[file_id]
457
        from_path = from_tree.id2path(file_id)
458
        to_path = to_tree.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
459
        return (file_id, (from_path, to_path), content_changed, (True, True),
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
460
            (from_entry.parent_id, to_entry.parent_id),
461
            (from_entry.name, to_entry.name),
462
            (from_entry.kind, to_entry.kind),
463
            (from_entry.executable, to_entry.executable))
464
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
465
    def unchanged(self, tree, file_id):
466
        entry = tree.inventory[file_id]
467
        parent = entry.parent_id
468
        name = entry.name
469
        kind = entry.kind
470
        executable = entry.executable
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
471
        path = tree.id2path(file_id)
472
        return (file_id, (path, path), False, (True, True),
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
473
               (parent, parent), (name, name), (kind, kind),
474
               (executable, executable))
475
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
476
    def unversioned(self, tree, path):
477
        """Create an unversioned result."""
478
        _, basename = os.path.split(path)
479
        kind = file_kind(tree.abspath(path))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
480
        return (None, (None, path), True, (False, False), (None, None),
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
481
                (None, basename), (None, kind),
482
                (None, False))
483
2012.1.1 by Aaron Bentley
Implement change iterator
484
    def test_empty_to_abc_content(self):
485
        tree1 = self.make_branch_and_tree('1')
486
        tree2 = self.make_to_branch_and_tree('2')
487
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
488
        tree2 = self.get_tree_no_parents_abc_content(tree2)
489
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2255.2.118 by Robert Collins
Change _iter_changes tests to lock the tested trees - its an iterator interface so implicit locks dont ensure the tree is locked - callers need to lock and thus so do our tests.
490
        tree1.lock_read()
491
        tree2.lock_read()
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
492
        expected_results = sorted([
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
493
            self.added(tree2, 'root-id'),
494
            self.added(tree2, 'a-id'),
495
            self.added(tree2, 'b-id'),
496
            self.added(tree2, 'c-id'),
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
497
            self.deleted(tree1, 'empty-root-id')])
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
498
        tree1.unlock()
499
        tree2.unlock()
500
        self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
501
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
502
    def test_empty_to_abc_content_a_only(self):
503
        tree1 = self.make_branch_and_tree('1')
504
        tree2 = self.make_to_branch_and_tree('2')
505
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
506
        tree2 = self.get_tree_no_parents_abc_content(tree2)
507
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
508
        tree1.lock_read()
509
        tree2.lock_read()
510
        self.assertEqual(
511
            [self.added(tree2, 'a-id')],
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
512
            self.do_iter_changes(tree1, tree2, specific_files=['a']))
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
513
        tree1.unlock()
514
        tree2.unlock()
515
516
    def test_abc_content_to_empty_to_abc_content_a_only(self):
517
        tree1 = self.make_branch_and_tree('1')
518
        tree2 = self.make_to_branch_and_tree('2')
519
        tree1 = self.get_tree_no_parents_abc_content(tree1)
520
        tree2 = self.get_tree_no_parents_no_content(tree2)
521
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
522
        tree1.lock_read()
523
        tree2.lock_read()
524
        self.assertEqual(
525
            [self.deleted(tree1, 'a-id')],
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
526
            self.do_iter_changes(tree1, tree2, specific_files=['a']))
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
527
        tree1.unlock()
528
        tree2.unlock()
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
529
530
    def test_empty_to_abc_content_a_and_c_only(self):
531
        tree1 = self.make_branch_and_tree('1')
532
        tree2 = self.make_to_branch_and_tree('2')
533
        tree1 = self.get_tree_no_parents_no_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
534
        tree2 = self.get_tree_no_parents_abc_content(tree2)
535
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2255.2.118 by Robert Collins
Change _iter_changes tests to lock the tested trees - its an iterator interface so implicit locks dont ensure the tree is locked - callers need to lock and thus so do our tests.
536
        tree1.lock_read()
537
        tree2.lock_read()
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
538
        expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
539
        tree1.unlock()
540
        tree2.unlock()
541
        self.assertEqual(expected_result,
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
542
            self.do_iter_changes(tree1, tree2, specific_files=['a', 'b/c']))
2012.1.5 by Aaron Bentley
Implement specific file id and dangling id handling
543
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
544
    def test_abc_content_to_empty(self):
2012.1.1 by Aaron Bentley
Implement change iterator
545
        tree1 = self.make_branch_and_tree('1')
546
        tree2 = self.make_to_branch_and_tree('2')
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
547
        tree1 = self.get_tree_no_parents_abc_content(tree1)
548
        tree2 = self.get_tree_no_parents_no_content(tree2)
549
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
550
        tree1.lock_read()
551
        tree2.lock_read()
2012.1.1 by Aaron Bentley
Implement change iterator
552
        def deleted(file_id):
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
553
            entry = tree1.inventory[file_id]
554
            path = tree1.id2path(file_id)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
555
            return (file_id, (path, None), True, (True, False),
2012.1.1 by Aaron Bentley
Implement change iterator
556
                    (entry.parent_id, None),
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
557
                    (entry.name, None), (entry.kind, None),
2012.1.1 by Aaron Bentley
Implement change iterator
558
                    (entry.executable, None))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
559
        expected_results = sorted([
560
            self.added(tree2, 'empty-root-id'),
561
            deleted('root-id'), deleted('a-id'),
562
            deleted('b-id'), deleted('c-id')])
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
563
        tree1.unlock()
564
        tree2.unlock()
565
        self.assertEqual(
566
            expected_results,
567
            self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
568
569
    def test_content_modification(self):
570
        tree1 = self.make_branch_and_tree('1')
571
        tree2 = self.make_to_branch_and_tree('2')
572
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
573
        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
574
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
575
        root_id = tree1.path2id('')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
576
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
577
                           (root_id, root_id), ('a', 'a'),
578
                           ('file', 'file'), (False, False))],
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
579
                         self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
580
581
    def test_meta_modification(self):
582
        tree1 = self.make_branch_and_tree('1')
583
        tree2 = self.make_to_branch_and_tree('2')
584
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
585
        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
586
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
587
        self.assertEqual([('c-id', ('b/c', 'b/c'), False, (True, True),
588
                           ('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
589
                          (False, True))],
590
                         self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
591
2255.7.6 by Robert Collins
Test for iterating changes past empty directories.
592
    def test_empty_dir(self):
593
        """an empty dir should not cause glitches to surrounding files."""
594
        tree1 = self.make_branch_and_tree('1')
595
        tree2 = self.make_to_branch_and_tree('2')
596
        tree1 = self.get_tree_no_parents_abc_content(tree1)
597
        tree2 = self.get_tree_no_parents_abc_content(tree2)
598
        # the pathname is chosen to fall between 'a' and 'b'.
599
        self.build_tree(['1/a-empty/', '2/a-empty/'])
600
        tree1.add(['a-empty'], ['a-empty'])
601
        tree2.add(['a-empty'], ['a-empty'])
602
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
603
        expected = []
604
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
605
2012.1.1 by Aaron Bentley
Implement change iterator
606
    def test_file_rename(self):
607
        tree1 = self.make_branch_and_tree('1')
608
        tree2 = self.make_to_branch_and_tree('2')
609
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
610
        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
611
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
612
        root_id = tree1.path2id('')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
613
        self.assertEqual([('a-id', ('a', 'd'), False, (True, True),
614
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
615
                           (False, False))],
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
616
                         self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
617
618
    def test_file_rename_and_modification(self):
619
        tree1 = self.make_branch_and_tree('1')
620
        tree2 = self.make_to_branch_and_tree('2')
621
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
622
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
623
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
624
        root_id = tree1.path2id('')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
625
        self.assertEqual([('a-id', ('a', 'd'), True, (True, True),
626
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
627
                           (False, False))],
628
                         self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
629
630
    def test_file_rename_and_meta_modification(self):
631
        tree1 = self.make_branch_and_tree('1')
632
        tree2 = self.make_to_branch_and_tree('2')
633
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
634
        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
635
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
636
        root_id = tree1.path2id('')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
637
        self.assertEqual([('c-id', ('b/c', 'e'), False, (True, True),
638
                           ('b-id', root_id), ('c', 'e'), ('file', 'file'),
639
                           (False, True))],
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
640
                         self.do_iter_changes(tree1, tree2))
2012.1.1 by Aaron Bentley
Implement change iterator
641
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
642
    def test_missing_in_target(self):
643
        """Test with the target files versioned but absent from disk."""
644
        tree1 = self.make_branch_and_tree('1')
645
        tree2 = self.make_to_branch_and_tree('2')
646
        tree1 = self.get_tree_no_parents_abc_content(tree1)
647
        tree2 = self.get_tree_no_parents_abc_content(tree2)
648
        os.unlink('2/a')
649
        shutil.rmtree('2/b')
650
        # TODO ? have a symlink here?
651
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
652
        root_id = tree1.path2id('')
653
        expected = sorted([
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
654
            self.missing('a-id', 'a', 'a', root_id, 'file'),
655
            self.missing('b-id', 'b', 'b', root_id, 'directory'),
656
            self.missing('c-id', 'b/c', 'b/c', 'b-id', 'file'),
657
            ])
658
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
659
660
    def test_missing_and_renamed(self):
661
        tree1 = self.make_branch_and_tree('tree1')
662
        tree2 = self.make_to_branch_and_tree('tree2')
663
        self.build_tree(['tree1/file'])
664
        tree1.add(['file'], ['file-id'])
665
        self.build_tree(['tree2/directory/'])
666
        tree2.add(['directory'], ['file-id'])
667
        os.rmdir('tree2/directory')
668
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
669
        tree1.lock_read()
670
        self.addCleanup(tree1.unlock)
671
        tree2.lock_read()
672
        self.addCleanup(tree2.unlock)
673
        root_id = tree1.path2id('')
674
        expected = sorted([
675
            self.missing('file-id', 'file', 'directory', root_id, 'file'),
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
676
            ])
677
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
678
2012.1.1 by Aaron Bentley
Implement change iterator
679
    def test_unchanged_with_renames_and_modifications(self):
680
        """want_unchanged should generate a list of unchanged entries."""
681
        tree1 = self.make_branch_and_tree('1')
682
        tree2 = self.make_to_branch_and_tree('2')
683
        tree1 = self.get_tree_no_parents_abc_content(tree1)
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
684
        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
685
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
686
        root_id = tree1.path2id('')
2255.2.118 by Robert Collins
Change _iter_changes tests to lock the tested trees - its an iterator interface so implicit locks dont ensure the tree is locked - callers need to lock and thus so do our tests.
687
        tree1.lock_read()
688
        self.addCleanup(tree1.unlock)
689
        tree2.lock_read()
690
        self.addCleanup(tree2.unlock)
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
691
        self.assertEqual(sorted([self.unchanged(tree1, root_id),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
692
            self.unchanged(tree1, 'b-id'),
693
            ('a-id', ('a', 'd'), True, (True, True),
694
             (root_id, root_id), ('a', 'd'), ('file', 'file'),
2255.7.4 by Robert Collins
Test InterTree._iter_changes with missing (absent but versioned) files.
695
            (False, False)), self.unchanged(tree1, 'c-id')]),
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
696
            self.do_iter_changes(tree1, tree2, include_unchanged=True))
2100.3.20 by Aaron Bentley
Implement tree comparison for tree references
697
698
    def test_compare_subtrees(self):
699
        """want_unchanged should generate a list of unchanged entries."""
700
        tree1 = self.make_branch_and_tree('1')
2255.9.2 by Martin Pool
test_compare_subtrees runs against all trees that claim to support
701
        if not tree1.supports_tree_reference():
702
            raise tests.TestSkipped('Tree %s does not support references'
703
                % (tree1,))
2100.3.20 by Aaron Bentley
Implement tree comparison for tree references
704
        tree1.set_root_id('root-id')
705
        subtree1 = self.make_branch_and_tree('1/sub')
706
        subtree1.set_root_id('subtree-id')
2255.9.2 by Martin Pool
test_compare_subtrees runs against all trees that claim to support
707
        tree1.add_reference(subtree1)
2100.3.20 by Aaron Bentley
Implement tree comparison for tree references
708
709
        tree2 = self.make_to_branch_and_tree('2')
2255.9.2 by Martin Pool
test_compare_subtrees runs against all trees that claim to support
710
        if not tree2.supports_tree_reference():
711
            raise tests.TestSkipped('Tree %s does not support references'
712
                % (tree2,))
2100.3.20 by Aaron Bentley
Implement tree comparison for tree references
713
        tree2.set_root_id('root-id')
714
        subtree2 = self.make_to_branch_and_tree('2/sub')
715
        subtree2.set_root_id('subtree-id')
716
        tree2.add_reference(subtree2)
717
        self.assertEqual([], list(tree2._iter_changes(tree1)))
718
        subtree1.commit('commit', rev_id='commit-a')
719
        self.assertEqual([('subtree-id',
720
                           'sub',
721
                           True,
722
                           (True, True),
723
                           ('root-id', 'root-id'),
724
                           ('sub', 'sub'),
725
                           ('tree-reference', 'tree-reference'),
726
                           (False, False))], 
727
                         list(tree2._iter_changes(tree1)))
2255.2.160 by Martin Pool
(merge) updates from dirstate branch
728
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
729
    def test_default_ignores_unversioned_files(self):
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
730
        tree1 = self.make_branch_and_tree('tree1')
731
        tree2 = self.make_to_branch_and_tree('tree2')
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
732
        self.build_tree(['tree1/a', 'tree1/c',
733
                         'tree2/a', 'tree2/b', 'tree2/c'])
734
        tree1.add(['a', 'c'], ['a-id', 'c-id'])
735
        tree2.add(['a', 'c'], ['a-id', 'c-id'])
736
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
737
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
738
        tree1.lock_read()
739
        self.addCleanup(tree1.unlock)
740
        tree2.lock_read()
741
        self.addCleanup(tree2.unlock)
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
742
743
        # We should ignore the fact that 'b' exists in tree-2
744
        # because the want_unversioned parameter was not given.
745
        expected = sorted([
746
            self.content_changed(tree2, 'a-id'),
747
            self.content_changed(tree2, 'c-id'),
748
            ])
2255.7.2 by Robert Collins
Add a (currently) disabled test for unversioned paths in the target tree with _iter_changes.
749
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
750
2255.7.85 by Robert Collins
Teach _iter_changes to gather unversioned path details upon request.
751
    def test_unversioned_paths_in_tree(self):
752
        tree1 = self.make_branch_and_tree('tree1')
753
        tree2 = self.make_to_branch_and_tree('tree2')
754
        self.build_tree(['tree2/file', 'tree2/dir/'])
755
        # try:
756
        os.symlink('target', 'tree2/link')
757
        links_supported = True
758
        # except ???:
759
        #   links_supported = False
760
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
761
        tree1.lock_read()
762
        self.addCleanup(tree1.unlock)
763
        tree2.lock_read()
764
        self.addCleanup(tree2.unlock)
765
        expected = [
766
            self.unversioned(tree2, 'file'),
767
            self.unversioned(tree2, 'dir'),
768
            ]
769
        if links_supported:
770
            expected.append(self.unversioned(tree2, 'link'))
771
        expected = sorted(expected)
772
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
773
            want_unversioned=True))
774
775
    def test_unversioned_paths_in_tree_specific_files(self):
776
        tree1 = self.make_branch_and_tree('tree1')
777
        tree2 = self.make_to_branch_and_tree('tree2')
778
        self.build_tree(['tree2/file', 'tree2/dir/'])
779
        # try:
780
        os.symlink('target', 'tree2/link')
781
        links_supported = True
782
        # except ???:
783
        #   links_supported = False
784
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
785
        tree1.lock_read()
786
        self.addCleanup(tree1.unlock)
787
        tree2.lock_read()
788
        self.addCleanup(tree2.unlock)
789
        expected = [
790
            self.unversioned(tree2, 'file'),
791
            self.unversioned(tree2, 'dir'),
792
            ]
793
        specific_files=['file', 'dir']
794
        if links_supported:
795
            expected.append(self.unversioned(tree2, 'link'))
796
            specific_files.append('link')
797
        expected = sorted(expected)
798
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
799
            specific_files=specific_files, require_versioned=False,
800
            want_unversioned=True))
801
802
    def test_unversioned_paths_in_target_matching_source_old_names(self):
803
        # its likely that naive implementations of unversioned file support
804
        # will fail if the path was versioned, but is not any more, 
805
        # due to a rename, not due to unversioning it.
806
        # That is, if the old tree has a versioned file 'foo', and
807
        # the new tree has the same file but versioned as 'bar', and also
808
        # has an unknown file 'foo', we should get back output for
809
        # both foo and bar.
810
        tree1 = self.make_branch_and_tree('tree1')
811
        tree2 = self.make_to_branch_and_tree('tree2')
812
        self.build_tree(['tree2/file', 'tree2/dir/',
813
            'tree1/file', 'tree2/movedfile',
814
            'tree1/dir/', 'tree2/moveddir/'])
815
        # try:
816
        os.symlink('target', 'tree1/link')
817
        os.symlink('target', 'tree2/link')
818
        os.symlink('target', 'tree2/movedlink')
819
        links_supported = True
820
        # except ???:
821
        #   links_supported = False
822
        tree1.add(['file', 'dir', 'link'], ['file-id', 'dir-id', 'link-id'])
823
        tree2.add(['movedfile', 'moveddir', 'movedlink'],
824
            ['file-id', 'dir-id', 'link-id'])
825
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
826
        root_id = tree1.path2id('')
827
        tree1.lock_read()
828
        self.addCleanup(tree1.unlock)
829
        tree2.lock_read()
830
        self.addCleanup(tree2.unlock)
831
        expected = [
832
            self.renamed(tree1, tree2, 'dir-id', False),
833
            self.renamed(tree1, tree2, 'file-id', True),
834
            self.unversioned(tree2, 'file'),
835
            self.unversioned(tree2, 'dir'),
836
            ]
837
        specific_files=['file', 'dir']
838
        if links_supported:
839
            expected.append(self.renamed(tree1, tree2, 'link-id', False))
840
            expected.append(self.unversioned(tree2, 'link'))
841
            specific_files.append('link')
842
        expected = sorted(expected)
843
        # run once with, and once without specific files, to catch
844
        # potentially different code paths.
845
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
846
            require_versioned=False,
847
            want_unversioned=True))
848
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
849
            specific_files=specific_files, require_versioned=False,
850
            want_unversioned=True))
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
851
2255.7.87 by Robert Collins
Dont walk unversioned directories in _iter_changes.
852
    def test_unversioned_subtree_only_emits_root(self):
853
        tree1 = self.make_branch_and_tree('tree1')
854
        tree2 = self.make_to_branch_and_tree('tree2')
855
        self.build_tree(['tree2/dir/', 'tree2/dir/file'])
856
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
857
        expected = [
858
            self.unversioned(tree2, 'dir'),
859
            ]
860
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
861
            want_unversioned=True))
862
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
863
    def make_trees_with_symlinks(self):
864
        tree1 = self.make_branch_and_tree('tree1')
865
        tree2 = self.make_to_branch_and_tree('tree2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
866
        tree2.set_root_id(tree1.get_root_id())
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
867
        self.build_tree(['tree1/fromfile', 'tree1/fromdir/'])
868
        self.build_tree(['tree2/tofile', 'tree2/todir/', 'tree2/unknown'])
869
        # try:
870
        os.symlink('original', 'tree1/changed')
871
        os.symlink('original', 'tree1/removed')
872
        os.symlink('original', 'tree1/tofile')
873
        os.symlink('original', 'tree1/todir')
874
        # we make the unchanged link point at unknown to catch incorrect
875
        # symlink-following code in the specified_files test.
876
        os.symlink('unknown', 'tree1/unchanged')
877
        os.symlink('new',      'tree2/added')
878
        os.symlink('new',      'tree2/changed')
879
        os.symlink('new',      'tree2/fromfile')
880
        os.symlink('new',      'tree2/fromdir')
881
        os.symlink('unknown', 'tree2/unchanged')
882
        from_paths_and_ids = [
883
            'fromdir',
884
            'fromfile',
885
            'changed',
886
            'removed',
887
            'todir',
888
            'tofile',
889
            'unchanged',
890
            ]
891
        to_paths_and_ids = [
892
            'added',
893
            'fromdir',
894
            'fromfile',
895
            'changed',
896
            'todir',
897
            'tofile',
898
            'unchanged',
899
            ]
900
        tree1.add(from_paths_and_ids, from_paths_and_ids)
901
        tree2.add(to_paths_and_ids, to_paths_and_ids)
902
        # except ???:
903
        #   raise TestSkipped('OS does not support symlinks')
904
        #   links_supported = False
905
        return self.mutable_trees_to_test_trees(tree1, tree2)
906
2255.2.182 by Martin Pool
merge dirstate and trunk
907
    def make_trees_with_subtrees(self):
908
        # trees containing tree references
909
        # TODO: might have to skip if the format can't do tree references
910
        tree1 = self.make_branch_and_tree('tree1')
911
        tree2 = self.make_to_branch_and_tree('tree2')
912
        self.build_tree(['tree1/fromdir/', 'tree1/common/',
913
            'tree2/todir/', 'tree2/common/'])
914
        # TODO: actually add the references
915
        return self.mutable_trees_to_test_trees(tree1, tree2)
916
2255.7.88 by Robert Collins
Enable InterTree._iter_changes symlink tests.
917
    def test_versioned_symlinks(self):
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
918
        tree1, tree2 = self.make_trees_with_symlinks()
919
        root_id = tree1.path2id('')
920
        tree1.lock_read()
921
        self.addCleanup(tree1.unlock)
922
        tree2.lock_read()
923
        self.addCleanup(tree2.unlock)
924
        expected = [
925
            self.unchanged(tree1, tree1.path2id('')),
926
            self.added(tree2, 'added'),
927
            self.content_changed(tree2, 'changed'),
928
            self.kind_changed(tree1, tree2, 'fromdir'),
929
            self.kind_changed(tree1, tree2, 'fromfile'),
930
            self.deleted(tree1, 'removed'),
931
            self.unchanged(tree2, 'unchanged'),
932
            self.unversioned(tree2, 'unknown'),
933
            self.kind_changed(tree1, tree2, 'todir'),
934
            self.kind_changed(tree1, tree2, 'tofile'),
935
            ]
936
        expected = sorted(expected)
2255.7.88 by Robert Collins
Enable InterTree._iter_changes symlink tests.
937
        self.assertEqual(expected,
938
            self.do_iter_changes(tree1, tree2, include_unchanged=True,
939
                want_unversioned=True))
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
940
2255.7.88 by Robert Collins
Enable InterTree._iter_changes symlink tests.
941
    def test_versioned_symlinks_specific_files(self):
2255.7.3 by Robert Collins
Add tests for _iter_changes with symlinks, disabled until unversioned file support is added, as that affects the test expected value.
942
        tree1, tree2 = self.make_trees_with_symlinks()
943
        root_id = tree1.path2id('')
944
        tree1.lock_read()
945
        self.addCleanup(tree1.unlock)
946
        tree2.lock_read()
947
        self.addCleanup(tree2.unlock)
948
        expected = [
949
            self.added(tree2, 'added'),
950
            self.content_changed(tree2, 'changed'),
951
            self.kind_changed(tree1, tree2, 'fromdir'),
952
            self.kind_changed(tree1, tree2, 'fromfile'),
953
            self.deleted(tree1, 'removed'),
954
            self.kind_changed(tree1, tree2, 'todir'),
955
            self.kind_changed(tree1, tree2, 'tofile'),
956
            ]
957
        expected = sorted(expected)
958
        # we should get back just the changed links. We pass in 'unchanged' to
959
        # make sure that it is correctly not returned - and neither is the
960
        # unknown path 'unknown' which it points at.
961
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
962
            specific_files=['added', 'changed', 'fromdir', 'fromfile',
963
            'removed', 'unchanged', 'todir', 'tofile']))
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
964
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
965
    def test_tree_with_special_names(self):
2255.7.15 by John Arbash Meinel
Try to create an intertree test that exposes the walkdir vs dirstate mismatch. No luck yet.
966
        tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
967
        tree1.lock_read()
968
        self.addCleanup(tree1.unlock)
969
        tree2.lock_read()
970
        self.addCleanup(tree2.unlock)
971
        expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
972
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
2255.7.22 by John Arbash Meinel
add a test that shows _iter_changes works when only contents have changed, and nothing is considered newly added.
973
974
    def test_trees_with_special_names(self):
975
        tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
976
        tree1.lock_read()
977
        self.addCleanup(tree1.unlock)
978
        tree2.lock_read()
979
        self.addCleanup(tree2.unlock)
980
        expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
981
                          if f_id.endswith('_f-id'))
982
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
2255.7.34 by John Arbash Meinel
Clean up test_bad_files, and fix a bug in _iter_changes when
983
2255.2.182 by Martin Pool
merge dirstate and trunk
984
    def test_trees_with_subtrees(self):
985
        tree1, tree2 = self.make_trees_with_subtrees()
986
        self.do_iter_changes(tree1, tree2)
987
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
988
    def test_trees_with_deleted_dir(self):
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
989
        tree1 = self.make_branch_and_tree('tree1')
990
        tree2 = self.make_to_branch_and_tree('tree2')
2255.2.161 by Martin Pool
merge some of dirstate, update comparison tests to keep tree roots the same unless they're meant to differ
991
        tree2.set_root_id(tree1.get_root_id())
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
992
        self.build_tree(['tree1/a', 'tree1/b/', 'tree1/b/c',
993
                         'tree1/b/d/', 'tree1/b/d/e', 'tree1/f/', 'tree1/f/g',
994
                         'tree2/a', 'tree2/f/', 'tree2/f/g'])
995
        tree1.add(['a', 'b', 'b/c', 'b/d/', 'b/d/e', 'f', 'f/g'],
996
                  ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id', 'g-id'])
997
        tree2.add(['a', 'f', 'f/g'], ['a-id', 'f-id', 'g-id'])
998
999
        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
1000
        tree1.lock_read()
1001
        self.addCleanup(tree1.unlock)
1002
        tree2.lock_read()
1003
        self.addCleanup(tree2.unlock)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1004
        # We should notice that 'b' and all its children are deleted
2255.7.35 by John Arbash Meinel
Handle the case when a directory has been removed, and isn't the last entry.
1005
        expected = sorted([
1006
            self.content_changed(tree2, 'a-id'),
1007
            self.content_changed(tree2, 'g-id'),
1008
            self.deleted(tree1, 'b-id'),
1009
            self.deleted(tree1, 'c-id'),
1010
            self.deleted(tree1, 'd-id'),
1011
            self.deleted(tree1, 'e-id'),
1012
            ])
1013
        self.assertEqual(expected, self.do_iter_changes(tree1, tree2))