~bzr-pqm/bzr/bzr.dev

3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
1
# Copyright (C) 2006, 2008 Canonical Ltd
1852.8.2 by Robert Collins
Add InterTree class to represent InterTree operations.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1852.8.2 by Robert Collins
Add InterTree class to represent InterTree operations.
16
17
"""Tests for Tree and InterTree."""
18
3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
19
from bzrlib import (
20
    errors,
21
    revision,
22
    tests,
23
    tree as _mod_tree,
24
    )
1852.8.2 by Robert Collins
Add InterTree class to represent InterTree operations.
25
from bzrlib.tests import TestCaseWithTransport
26
from bzrlib.tree import InterTree
27
28
29
class TestInterTree(TestCaseWithTransport):
30
31
    def test_revision_tree_revision_tree(self):
32
        # we should have an InterTree registered for RevisionTree to
33
        # RevisionTree.
34
        tree = self.make_branch_and_tree('.')
35
        rev_id = tree.commit('first post')
36
        rev_id2 = tree.commit('second post', allow_pointless=True)
37
        rev_tree = tree.branch.repository.revision_tree(rev_id)
38
        rev_tree2 = tree.branch.repository.revision_tree(rev_id2)
39
        optimiser = InterTree.get(rev_tree, rev_tree2)
40
        self.assertIsInstance(optimiser, InterTree)
41
        optimiser = InterTree.get(rev_tree2, rev_tree)
42
        self.assertIsInstance(optimiser, InterTree)
43
44
    def test_working_tree_revision_tree(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
45
        # we should have an InterTree available for WorkingTree to
1852.8.2 by Robert Collins
Add InterTree class to represent InterTree operations.
46
        # RevisionTree.
47
        tree = self.make_branch_and_tree('.')
48
        rev_id = tree.commit('first post')
49
        rev_tree = tree.branch.repository.revision_tree(rev_id)
50
        optimiser = InterTree.get(rev_tree, tree)
51
        self.assertIsInstance(optimiser, InterTree)
52
        optimiser = InterTree.get(tree, rev_tree)
53
        self.assertIsInstance(optimiser, InterTree)
54
55
    def test_working_tree_working_tree(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
56
        # we should have an InterTree available for WorkingTree to
1852.8.2 by Robert Collins
Add InterTree class to represent InterTree operations.
57
        # WorkingTree.
58
        tree = self.make_branch_and_tree('1')
59
        tree2 = self.make_branch_and_tree('2')
60
        optimiser = InterTree.get(tree, tree2)
61
        self.assertIsInstance(optimiser, InterTree)
62
        optimiser = InterTree.get(tree2, tree)
63
        self.assertIsInstance(optimiser, InterTree)
1852.8.4 by Robert Collins
Hook InterTree into Tree.
64
65
66
class RecordingOptimiser(InterTree):
67
68
    calls = []
69
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
70
    def compare(self, want_unchanged=False, specific_files=None,
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
71
        extra_trees=None, require_versioned=False, include_root=False,
72
        want_unversioned=False):
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
73
        self.calls.append(
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
74
            ('compare', self.source, self.target, want_unchanged,
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
75
             specific_files, extra_trees, require_versioned,
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
76
             include_root, want_unversioned)
1852.9.5 by Robert Collins
Add tests for require_versioned to the InterTree.compare() test suite.
77
            )
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
78
1852.8.4 by Robert Collins
Hook InterTree into Tree.
79
    @classmethod
80
    def is_compatible(klass, source, target):
81
        return True
82
83
84
class TestTree(TestCaseWithTransport):
85
86
    def test_compare_calls_InterTree_compare(self):
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
87
        """This test tests the way Tree.compare() uses InterTree."""
1852.8.4 by Robert Collins
Hook InterTree into Tree.
88
        old_optimisers = InterTree._optimisers
89
        try:
1910.2.15 by Aaron Bentley
Back out inter.get changes, make optimizers an ordered list
90
            InterTree._optimisers = []
1852.8.4 by Robert Collins
Hook InterTree into Tree.
91
            RecordingOptimiser.calls = []
92
            InterTree.register_optimiser(RecordingOptimiser)
93
            tree = self.make_branch_and_tree('1')
94
            tree2 = self.make_branch_and_tree('2')
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
95
            # do a series of calls:
96
            # trivial usage
1852.8.8 by Robert Collins
change Tree.compare to Tree.changes_from - its better for the common case.
97
            tree.changes_from(tree2)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
98
            # pass in all optional arguments by position
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
99
            tree.changes_from(tree2, 'unchanged', 'specific', 'extra',
1910.2.57 by Aaron Bentley
Got 0.9 bundles working, with root included by changes_from
100
                              'require', True)
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
101
            # pass in all optional arguments by keyword
1852.9.6 by Robert Collins
Merge the change from Tree.compare to Tree.changes_from.
102
            tree.changes_from(tree2,
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
103
                specific_files='specific',
104
                want_unchanged='unchanged',
105
                extra_trees='extra',
1852.9.5 by Robert Collins
Add tests for require_versioned to the InterTree.compare() test suite.
106
                require_versioned='require',
1910.2.57 by Aaron Bentley
Got 0.9 bundles working, with root included by changes_from
107
                include_root=True,
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
108
                want_unversioned=True,
1852.9.4 by Robert Collins
Add minimal test for Tree.compare(extra_trees=...).
109
                )
1852.8.4 by Robert Collins
Hook InterTree into Tree.
110
        finally:
111
            InterTree._optimisers = old_optimisers
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
112
        self.assertEqual(
113
            [
2255.7.90 by Robert Collins
Add unversioned path reporting to TreeDelta.
114
             ('compare', tree2, tree, False, None, None, False, False, False),
115
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
116
              'require', True, False),
117
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
118
              'require', True, True),
1852.9.3 by Robert Collins
Convert the test_delta tests to intertree_implementation and workingtree_implementation tests as appropriate.
119
            ], RecordingOptimiser.calls)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
120
121
    def test_changes_from_with_root(self):
122
        """Ensure the include_root option does what's expected."""
123
        wt = self.make_branch_and_tree('.')
124
        delta = wt.changes_from(wt.basis_tree())
125
        self.assertEqual(len(delta.added), 0)
4570.2.7 by Robert Collins
Fix misuse of tree.compare API in test_tree.py
126
        delta = wt.changes_from(wt.basis_tree(), include_root=True)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
127
        self.assertEqual(len(delta.added), 1)
128
        self.assertEqual(delta.added[0][0], '')
2655.2.1 by Marius Kruger
InterTree.compare and delta._compare_trees did not pass its
129
130
    def test_changes_from_with_require_versioned(self):
131
        """Ensure the require_versioned option does what's expected."""
132
        wt = self.make_branch_and_tree('.')
133
        self.build_tree(['known_file', 'unknown_file'])
134
        wt.add('known_file')
135
2655.2.2 by Marius Kruger
Rather use assertRaises in test_changes_from_with_require_versioned
136
        self.assertRaises(errors.PathsNotVersionedError,
137
            wt.changes_from, wt.basis_tree(), wt, specific_files=['known_file',
138
            'unknown_file'], require_versioned=True)
2655.2.1 by Marius Kruger
InterTree.compare and delta._compare_trees did not pass its
139
140
        # we need to pass a known file with an unknown file to get this to
141
        # fail when expected.
4570.2.7 by Robert Collins
Fix misuse of tree.compare API in test_tree.py
142
        delta = wt.changes_from(wt.basis_tree(),
2655.2.1 by Marius Kruger
InterTree.compare and delta._compare_trees did not pass its
143
            specific_files=['known_file', 'unknown_file'] ,
144
            require_versioned=False)
145
        self.assertEqual(len(delta.added), 1)
3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
146
147
148
class TestMultiWalker(TestCaseWithTransport):
149
150
    def assertStepOne(self, has_more, path, file_id, iterator):
151
        retval = _mod_tree.MultiWalker._step_one(iterator)
152
        if not has_more:
153
            self.assertIs(None, path)
154
            self.assertIs(None, file_id)
155
            self.assertEqual((False, None, None), retval)
156
        else:
157
            self.assertEqual((has_more, path, file_id),
158
                             (retval[0], retval[1], retval[2].file_id))
159
160
    def test__step_one_empty(self):
161
        tree = self.make_branch_and_tree('empty')
162
        repo = tree.branch.repository
163
        empty_tree = repo.revision_tree(revision.NULL_REVISION)
164
165
        iterator = empty_tree.iter_entries_by_dir()
166
        self.assertStepOne(False, None, None, iterator)
167
        self.assertStepOne(False, None, None, iterator)
168
169
    def test__step_one(self):
170
        tree = self.make_branch_and_tree('tree')
171
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
172
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
173
174
        iterator = tree.iter_entries_by_dir()
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
175
        tree.lock_read()
176
        self.addCleanup(tree.unlock)
177
3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
178
        root_id = tree.path2id('')
179
        self.assertStepOne(True, '', root_id, iterator)
180
        self.assertStepOne(True, 'a', 'a-id', iterator)
181
        self.assertStepOne(True, 'b', 'b-id', iterator)
182
        self.assertStepOne(True, 'b/c', 'c-id', iterator)
183
        self.assertStepOne(False, None, None, iterator)
184
        self.assertStepOne(False, None, None, iterator)
185
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
186
    def assertWalkerNext(self, exp_path, exp_file_id, master_has_node,
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
187
                         exp_other_paths, iterator):
188
        """Check what happens when we step the iterator.
189
190
        :param path: The path for this entry
191
        :param file_id: The file_id for this entry
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
192
        :param master_has_node: Does the master tree have this entry?
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
193
        :param exp_other_paths: A list of other_path values.
194
        :param iterator: The iterator to step
195
        """
196
        path, file_id, master_ie, other_values = iterator.next()
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
197
        self.assertEqual((exp_path, exp_file_id), (path, file_id),
198
                         'Master entry did not match')
199
        if master_has_node:
200
            self.assertIsNot(None, master_ie, 'master should have an entry')
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
201
        else:
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
202
            self.assertIs(None, master_ie, 'master should not have an entry')
203
        self.assertEqual(len(exp_other_paths), len(other_values),
204
                            'Wrong number of other entries')
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
205
        other_paths = []
206
        other_file_ids = []
207
        for path, ie in other_values:
208
            other_paths.append(path)
209
            if ie is None:
210
                other_file_ids.append(None)
211
            else:
212
                other_file_ids.append(ie.file_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
213
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
214
        exp_file_ids = []
215
        for path in exp_other_paths:
216
            if path is None:
217
                exp_file_ids.append(None)
218
            else:
219
                exp_file_ids.append(file_id)
220
        self.assertEqual(exp_other_paths, other_paths, "Other paths incorrect")
221
        self.assertEqual(exp_file_ids, other_file_ids,
222
                         "Other file_ids incorrect")
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
223
224
    def lock_and_get_basis_and_root_id(self, tree):
225
        tree.lock_read()
226
        self.addCleanup(tree.unlock)
227
        basis_tree = tree.basis_tree()
228
        basis_tree.lock_read()
229
        self.addCleanup(basis_tree.unlock)
230
        root_id = tree.path2id('')
231
        return basis_tree, root_id
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
232
3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
233
    def test_simple_stepping(self):
234
        tree = self.make_branch_and_tree('tree')
235
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
236
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
237
238
        tree.commit('first', rev_id='first-rev-id')
239
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
240
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
241
242
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
243
        iterator = walker.iter_all()
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
244
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
245
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
246
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
247
        self.assertWalkerNext(u'b/c', 'c-id', True, [u'b/c'], iterator)
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
248
        self.assertRaises(StopIteration, iterator.next)
249
250
    def test_master_has_extra(self):
251
        tree = self.make_branch_and_tree('tree')
252
        self.build_tree(['tree/a', 'tree/b/', 'tree/c', 'tree/d'])
253
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
254
255
        tree.commit('first', rev_id='first-rev-id')
256
257
        tree.add(['c'], ['c-id'])
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
258
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
259
260
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
261
        iterator = walker.iter_all()
262
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
263
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
264
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
265
        self.assertWalkerNext(u'c', 'c-id', True, [None], iterator)
266
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
267
        self.assertRaises(StopIteration, iterator.next)
268
269
    def test_master_renamed_to_earlier(self):
270
        """The record is still present, it just shows up early."""
271
        tree = self.make_branch_and_tree('tree')
272
        self.build_tree(['tree/a', 'tree/c', 'tree/d'])
273
        tree.add(['a', 'c', 'd'], ['a-id', 'c-id', 'd-id'])
274
        tree.commit('first', rev_id='first-rev-id')
275
        tree.rename_one('d', 'b')
276
277
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
278
279
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
280
        iterator = walker.iter_all()
281
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
282
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
283
        self.assertWalkerNext(u'b', 'd-id', True, [u'd'], iterator)
284
        self.assertWalkerNext(u'c', 'c-id', True, [u'c'], iterator)
285
        self.assertRaises(StopIteration, iterator.next)
286
287
    def test_master_renamed_to_later(self):
288
        tree = self.make_branch_and_tree('tree')
289
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
290
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
291
        tree.commit('first', rev_id='first-rev-id')
292
        tree.rename_one('b', 'e')
293
294
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
295
296
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
297
        iterator = walker.iter_all()
298
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
299
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
300
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
301
        self.assertWalkerNext(u'e', 'b-id', True, [u'b'], iterator)
302
        self.assertRaises(StopIteration, iterator.next)
303
3514.3.4 by John Arbash Meinel
Handle more cases when the other tree has extra nodes.
304
    def test_other_extra_in_middle(self):
3514.3.3 by John Arbash Meinel
Handle when the other tree has extra nodes, and we need to yield them.
305
        tree = self.make_branch_and_tree('tree')
306
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
307
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
308
        tree.commit('first', rev_id='first-rev-id')
309
        tree.remove(['b'])
310
311
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
312
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
313
        iterator = walker.iter_all()
314
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
315
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
316
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
3514.3.2 by John Arbash Meinel
Handle the case when a record is missing in base
317
        self.assertWalkerNext(u'b', 'b-id', False, [u'b'], iterator)
3514.3.1 by John Arbash Meinel
Start working on a special walker that can iterate several trees at once.
318
        self.assertRaises(StopIteration, iterator.next)
3514.3.4 by John Arbash Meinel
Handle more cases when the other tree has extra nodes.
319
320
    def test_other_extra_at_end(self):
321
        tree = self.make_branch_and_tree('tree')
322
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
323
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
324
        tree.commit('first', rev_id='first-rev-id')
325
        tree.remove(['d'])
326
327
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
328
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
329
        iterator = walker.iter_all()
330
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
331
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
332
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
333
        self.assertWalkerNext(u'd', 'd-id', False, [u'd'], iterator)
334
        self.assertRaises(StopIteration, iterator.next)
335
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
336
    def test_others_extra_at_end(self):
337
        tree = self.make_branch_and_tree('tree')
3514.3.6 by John Arbash Meinel
check when there are 3 other trees, rather than just 2
338
        self.build_tree(['tree/a', 'tree/b', 'tree/c', 'tree/d', 'tree/e'])
339
        tree.add(['a', 'b', 'c', 'd', 'e'],
340
                 ['a-id', 'b-id', 'c-id', 'd-id', 'e-id'])
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
341
        tree.commit('first', rev_id='first-rev-id')
3514.3.6 by John Arbash Meinel
check when there are 3 other trees, rather than just 2
342
        tree.remove(['e'])
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
343
        tree.commit('second', rev_id='second-rev-id')
3514.3.6 by John Arbash Meinel
check when there are 3 other trees, rather than just 2
344
        tree.remove(['d'])
345
        tree.commit('third', rev_id='third-rev-id')
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
346
        tree.remove(['c'])
347
348
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
349
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
3514.3.6 by John Arbash Meinel
check when there are 3 other trees, rather than just 2
350
        second_tree = tree.branch.repository.revision_tree('second-rev-id')
351
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree,
352
                                              second_tree])
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
353
        iterator = walker.iter_all()
3514.3.6 by John Arbash Meinel
check when there are 3 other trees, rather than just 2
354
        self.assertWalkerNext(u'', root_id, True, [u'', u'', u''], iterator)
355
        self.assertWalkerNext(u'a', 'a-id', True, [u'a', u'a', u'a'], iterator)
356
        self.assertWalkerNext(u'b', 'b-id', True, [u'b', u'b', u'b'], iterator)
357
        self.assertWalkerNext(u'c', 'c-id', False, [u'c', u'c', u'c'], iterator)
358
        self.assertWalkerNext(u'd', 'd-id', False, [None, u'd', u'd'], iterator)
359
        self.assertWalkerNext(u'e', 'e-id', False, [None, u'e', None], iterator)
3514.3.5 by John Arbash Meinel
Handle some edge cases when we have multiple other trees.
360
        self.assertRaises(StopIteration, iterator.next)
3514.3.10 by John Arbash Meinel
A mix-matched commit with things moving in each tree.
361
362
    def test_different_file_id_in_others(self):
363
        tree = self.make_branch_and_tree('tree')
364
        self.build_tree(['tree/a', 'tree/b', 'tree/c/'])
365
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
366
        tree.commit('first', rev_id='first-rev-id')
367
368
        tree.rename_one('b', 'c/d')
369
        self.build_tree(['tree/b'])
370
        tree.add(['b'], ['b2-id'])
371
        tree.commit('second', rev_id='second-rev-id')
372
373
        tree.rename_one('a', 'c/e')
374
        self.build_tree(['tree/a'])
375
        tree.add(['a'], ['a2-id'])
376
377
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
378
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
379
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree])
380
381
        iterator = walker.iter_all()
382
        self.assertWalkerNext(u'', root_id, True, [u'', u''], iterator)
383
        self.assertWalkerNext(u'a', 'a2-id', True, [None, None], iterator)
384
        self.assertWalkerNext(u'b', 'b2-id', True, [u'b', None], iterator)
385
        self.assertWalkerNext(u'c', 'c-id', True, [u'c', u'c'], iterator)
386
        self.assertWalkerNext(u'c/d', 'b-id', True, [u'c/d', u'b'], iterator)
387
        self.assertWalkerNext(u'c/e', 'a-id', True, [u'a', u'a'], iterator)
388
        self.assertRaises(StopIteration, iterator.next)
3514.3.12 by John Arbash Meinel
Found some problems in _path_key, and made sure to have proper testing of _cmp_paths_by_dirblock
389
390
    def assertCmpByDirblock(self, cmp_val, path1, path2):
391
        self.assertEqual(cmp_val,
392
            _mod_tree.MultiWalker._cmp_path_by_dirblock(path1, path2))
393
394
    def test__cmp_path_by_dirblock(self):
395
        # We only support Unicode strings at this point
396
        self.assertRaises(TypeError,
397
            _mod_tree.MultiWalker._cmp_path_by_dirblock, '', 'b')
398
        self.assertCmpByDirblock(0, u'', u'')
399
        self.assertCmpByDirblock(0, u'a', u'a')
400
        self.assertCmpByDirblock(0, u'a/b', u'a/b')
401
        self.assertCmpByDirblock(0, u'a/b/c', u'a/b/c')
402
        self.assertCmpByDirblock(1, u'a-a', u'a')
403
        self.assertCmpByDirblock(-1, u'a-a', u'a/a')
404
        self.assertCmpByDirblock(-1, u'a=a', u'a/a')
405
        self.assertCmpByDirblock(1, u'a-a/a', u'a/a')
406
        self.assertCmpByDirblock(1, u'a=a/a', u'a/a')
407
        self.assertCmpByDirblock(1, u'a-a/a', u'a/a/a')
408
        self.assertCmpByDirblock(1, u'a=a/a', u'a/a/a')
409
        self.assertCmpByDirblock(1, u'a-a/a/a', u'a/a/a')
410
        self.assertCmpByDirblock(1, u'a=a/a/a', u'a/a/a')
411
3514.3.13 by John Arbash Meinel
One code path was using a tuple, another a plain path
412
    def assertPathToKey(self, expected, path):
413
        self.assertEqual(expected, _mod_tree.MultiWalker._path_to_key(path))
3514.3.12 by John Arbash Meinel
Found some problems in _path_key, and made sure to have proper testing of _cmp_paths_by_dirblock
414
3514.3.13 by John Arbash Meinel
One code path was using a tuple, another a plain path
415
    def test__path_to_key(self):
416
        self.assertPathToKey(([u''], u''), u'')
417
        self.assertPathToKey(([u''], u'a'), u'a')
418
        self.assertPathToKey(([u'a'], u'b'), u'a/b')
419
        self.assertPathToKey(([u'a', u'b'], u'c'), u'a/b/c')