~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_tree.py

Turn completion assertions into separate methods.

Many common assertions used to be expressed as arguments to the complete
method.  This makes the checks more explicit, and the code easier to read.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2009, 2011 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""Tests for Tree and InterTree."""
18
 
 
19
 
from bzrlib import (
20
 
    errors,
21
 
    revision,
22
 
    tree as _mod_tree,
23
 
    )
24
 
from bzrlib.tests import TestCaseWithTransport
25
 
from bzrlib.tree import InterTree
26
 
 
27
 
 
28
 
class TestInterTree(TestCaseWithTransport):
29
 
 
30
 
    def test_revision_tree_revision_tree(self):
31
 
        # we should have an InterTree registered for RevisionTree to
32
 
        # RevisionTree.
33
 
        tree = self.make_branch_and_tree('.')
34
 
        rev_id = tree.commit('first post')
35
 
        rev_id2 = tree.commit('second post', allow_pointless=True)
36
 
        rev_tree = tree.branch.repository.revision_tree(rev_id)
37
 
        rev_tree2 = tree.branch.repository.revision_tree(rev_id2)
38
 
        optimiser = InterTree.get(rev_tree, rev_tree2)
39
 
        self.assertIsInstance(optimiser, InterTree)
40
 
        optimiser = InterTree.get(rev_tree2, rev_tree)
41
 
        self.assertIsInstance(optimiser, InterTree)
42
 
 
43
 
    def test_working_tree_revision_tree(self):
44
 
        # we should have an InterTree available for WorkingTree to
45
 
        # RevisionTree.
46
 
        tree = self.make_branch_and_tree('.')
47
 
        rev_id = tree.commit('first post')
48
 
        rev_tree = tree.branch.repository.revision_tree(rev_id)
49
 
        optimiser = InterTree.get(rev_tree, tree)
50
 
        self.assertIsInstance(optimiser, InterTree)
51
 
        optimiser = InterTree.get(tree, rev_tree)
52
 
        self.assertIsInstance(optimiser, InterTree)
53
 
 
54
 
    def test_working_tree_working_tree(self):
55
 
        # we should have an InterTree available for WorkingTree to
56
 
        # WorkingTree.
57
 
        tree = self.make_branch_and_tree('1')
58
 
        tree2 = self.make_branch_and_tree('2')
59
 
        optimiser = InterTree.get(tree, tree2)
60
 
        self.assertIsInstance(optimiser, InterTree)
61
 
        optimiser = InterTree.get(tree2, tree)
62
 
        self.assertIsInstance(optimiser, InterTree)
63
 
 
64
 
 
65
 
class RecordingOptimiser(InterTree):
66
 
 
67
 
    calls = []
68
 
 
69
 
    def compare(self, want_unchanged=False, specific_files=None,
70
 
        extra_trees=None, require_versioned=False, include_root=False,
71
 
        want_unversioned=False):
72
 
        self.calls.append(
73
 
            ('compare', self.source, self.target, want_unchanged,
74
 
             specific_files, extra_trees, require_versioned,
75
 
             include_root, want_unversioned)
76
 
            )
77
 
 
78
 
    @classmethod
79
 
    def is_compatible(klass, source, target):
80
 
        return True
81
 
 
82
 
 
83
 
class TestTree(TestCaseWithTransport):
84
 
 
85
 
    def test_compare_calls_InterTree_compare(self):
86
 
        """This test tests the way Tree.compare() uses InterTree."""
87
 
        old_optimisers = InterTree._optimisers
88
 
        try:
89
 
            InterTree._optimisers = []
90
 
            RecordingOptimiser.calls = []
91
 
            InterTree.register_optimiser(RecordingOptimiser)
92
 
            tree = self.make_branch_and_tree('1')
93
 
            tree2 = self.make_branch_and_tree('2')
94
 
            # do a series of calls:
95
 
            # trivial usage
96
 
            tree.changes_from(tree2)
97
 
            # pass in all optional arguments by position
98
 
            tree.changes_from(tree2, 'unchanged', 'specific', 'extra',
99
 
                              'require', True)
100
 
            # pass in all optional arguments by keyword
101
 
            tree.changes_from(tree2,
102
 
                specific_files='specific',
103
 
                want_unchanged='unchanged',
104
 
                extra_trees='extra',
105
 
                require_versioned='require',
106
 
                include_root=True,
107
 
                want_unversioned=True,
108
 
                )
109
 
        finally:
110
 
            InterTree._optimisers = old_optimisers
111
 
        self.assertEqual(
112
 
            [
113
 
             ('compare', tree2, tree, False, None, None, False, False, False),
114
 
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
115
 
              'require', True, False),
116
 
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
117
 
              'require', True, True),
118
 
            ], RecordingOptimiser.calls)
119
 
 
120
 
    def test_changes_from_with_root(self):
121
 
        """Ensure the include_root option does what's expected."""
122
 
        wt = self.make_branch_and_tree('.')
123
 
        delta = wt.changes_from(wt.basis_tree())
124
 
        self.assertEqual(len(delta.added), 0)
125
 
        delta = wt.changes_from(wt.basis_tree(), include_root=True)
126
 
        self.assertEqual(len(delta.added), 1)
127
 
        self.assertEqual(delta.added[0][0], '')
128
 
 
129
 
    def test_changes_from_with_require_versioned(self):
130
 
        """Ensure the require_versioned option does what's expected."""
131
 
        wt = self.make_branch_and_tree('.')
132
 
        self.build_tree(['known_file', 'unknown_file'])
133
 
        wt.add('known_file')
134
 
 
135
 
        self.assertRaises(errors.PathsNotVersionedError,
136
 
            wt.changes_from, wt.basis_tree(), wt, specific_files=['known_file',
137
 
            'unknown_file'], require_versioned=True)
138
 
 
139
 
        # we need to pass a known file with an unknown file to get this to
140
 
        # fail when expected.
141
 
        delta = wt.changes_from(wt.basis_tree(),
142
 
            specific_files=['known_file', 'unknown_file'] ,
143
 
            require_versioned=False)
144
 
        self.assertEqual(len(delta.added), 1)
145
 
 
146
 
 
147
 
class TestMultiWalker(TestCaseWithTransport):
148
 
 
149
 
    def assertStepOne(self, has_more, path, file_id, iterator):
150
 
        retval = _mod_tree.MultiWalker._step_one(iterator)
151
 
        if not has_more:
152
 
            self.assertIs(None, path)
153
 
            self.assertIs(None, file_id)
154
 
            self.assertEqual((False, None, None), retval)
155
 
        else:
156
 
            self.assertEqual((has_more, path, file_id),
157
 
                             (retval[0], retval[1], retval[2].file_id))
158
 
 
159
 
    def test__step_one_empty(self):
160
 
        tree = self.make_branch_and_tree('empty')
161
 
        repo = tree.branch.repository
162
 
        empty_tree = repo.revision_tree(revision.NULL_REVISION)
163
 
 
164
 
        iterator = empty_tree.iter_entries_by_dir()
165
 
        self.assertStepOne(False, None, None, iterator)
166
 
        self.assertStepOne(False, None, None, iterator)
167
 
 
168
 
    def test__step_one(self):
169
 
        tree = self.make_branch_and_tree('tree')
170
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
171
 
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
172
 
 
173
 
        iterator = tree.iter_entries_by_dir()
174
 
        tree.lock_read()
175
 
        self.addCleanup(tree.unlock)
176
 
 
177
 
        root_id = tree.path2id('')
178
 
        self.assertStepOne(True, '', root_id, iterator)
179
 
        self.assertStepOne(True, 'a', 'a-id', iterator)
180
 
        self.assertStepOne(True, 'b', 'b-id', iterator)
181
 
        self.assertStepOne(True, 'b/c', 'c-id', iterator)
182
 
        self.assertStepOne(False, None, None, iterator)
183
 
        self.assertStepOne(False, None, None, iterator)
184
 
 
185
 
    def assertWalkerNext(self, exp_path, exp_file_id, master_has_node,
186
 
                         exp_other_paths, iterator):
187
 
        """Check what happens when we step the iterator.
188
 
 
189
 
        :param path: The path for this entry
190
 
        :param file_id: The file_id for this entry
191
 
        :param master_has_node: Does the master tree have this entry?
192
 
        :param exp_other_paths: A list of other_path values.
193
 
        :param iterator: The iterator to step
194
 
        """
195
 
        path, file_id, master_ie, other_values = iterator.next()
196
 
        self.assertEqual((exp_path, exp_file_id), (path, file_id),
197
 
                         'Master entry did not match')
198
 
        if master_has_node:
199
 
            self.assertIsNot(None, master_ie, 'master should have an entry')
200
 
        else:
201
 
            self.assertIs(None, master_ie, 'master should not have an entry')
202
 
        self.assertEqual(len(exp_other_paths), len(other_values),
203
 
                            'Wrong number of other entries')
204
 
        other_paths = []
205
 
        other_file_ids = []
206
 
        for path, ie in other_values:
207
 
            other_paths.append(path)
208
 
            if ie is None:
209
 
                other_file_ids.append(None)
210
 
            else:
211
 
                other_file_ids.append(ie.file_id)
212
 
 
213
 
        exp_file_ids = []
214
 
        for path in exp_other_paths:
215
 
            if path is None:
216
 
                exp_file_ids.append(None)
217
 
            else:
218
 
                exp_file_ids.append(file_id)
219
 
        self.assertEqual(exp_other_paths, other_paths, "Other paths incorrect")
220
 
        self.assertEqual(exp_file_ids, other_file_ids,
221
 
                         "Other file_ids incorrect")
222
 
 
223
 
    def lock_and_get_basis_and_root_id(self, tree):
224
 
        tree.lock_read()
225
 
        self.addCleanup(tree.unlock)
226
 
        basis_tree = tree.basis_tree()
227
 
        basis_tree.lock_read()
228
 
        self.addCleanup(basis_tree.unlock)
229
 
        root_id = tree.path2id('')
230
 
        return basis_tree, root_id
231
 
 
232
 
    def test_simple_stepping(self):
233
 
        tree = self.make_branch_and_tree('tree')
234
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
235
 
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
236
 
 
237
 
        tree.commit('first', rev_id='first-rev-id')
238
 
 
239
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
240
 
 
241
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
242
 
        iterator = walker.iter_all()
243
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
244
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
245
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
246
 
        self.assertWalkerNext(u'b/c', 'c-id', True, [u'b/c'], iterator)
247
 
        self.assertRaises(StopIteration, iterator.next)
248
 
 
249
 
    def test_master_has_extra(self):
250
 
        tree = self.make_branch_and_tree('tree')
251
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/c', 'tree/d'])
252
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
253
 
 
254
 
        tree.commit('first', rev_id='first-rev-id')
255
 
 
256
 
        tree.add(['c'], ['c-id'])
257
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
258
 
 
259
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
260
 
        iterator = walker.iter_all()
261
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
262
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
263
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
264
 
        self.assertWalkerNext(u'c', 'c-id', True, [None], iterator)
265
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
266
 
        self.assertRaises(StopIteration, iterator.next)
267
 
 
268
 
    def test_master_renamed_to_earlier(self):
269
 
        """The record is still present, it just shows up early."""
270
 
        tree = self.make_branch_and_tree('tree')
271
 
        self.build_tree(['tree/a', 'tree/c', 'tree/d'])
272
 
        tree.add(['a', 'c', 'd'], ['a-id', 'c-id', 'd-id'])
273
 
        tree.commit('first', rev_id='first-rev-id')
274
 
        tree.rename_one('d', 'b')
275
 
 
276
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
277
 
 
278
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
279
 
        iterator = walker.iter_all()
280
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
281
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
282
 
        self.assertWalkerNext(u'b', 'd-id', True, [u'd'], iterator)
283
 
        self.assertWalkerNext(u'c', 'c-id', True, [u'c'], iterator)
284
 
        self.assertRaises(StopIteration, iterator.next)
285
 
 
286
 
    def test_master_renamed_to_later(self):
287
 
        tree = self.make_branch_and_tree('tree')
288
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
289
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
290
 
        tree.commit('first', rev_id='first-rev-id')
291
 
        tree.rename_one('b', 'e')
292
 
 
293
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
294
 
 
295
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
296
 
        iterator = walker.iter_all()
297
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
298
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
299
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
300
 
        self.assertWalkerNext(u'e', 'b-id', True, [u'b'], iterator)
301
 
        self.assertRaises(StopIteration, iterator.next)
302
 
 
303
 
    def test_other_extra_in_middle(self):
304
 
        tree = self.make_branch_and_tree('tree')
305
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
306
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
307
 
        tree.commit('first', rev_id='first-rev-id')
308
 
        tree.remove(['b'])
309
 
 
310
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
311
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
312
 
        iterator = walker.iter_all()
313
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
314
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
315
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
316
 
        self.assertWalkerNext(u'b', 'b-id', False, [u'b'], iterator)
317
 
        self.assertRaises(StopIteration, iterator.next)
318
 
 
319
 
    def test_other_extra_at_end(self):
320
 
        tree = self.make_branch_and_tree('tree')
321
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
322
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
323
 
        tree.commit('first', rev_id='first-rev-id')
324
 
        tree.remove(['d'])
325
 
 
326
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
327
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
328
 
        iterator = walker.iter_all()
329
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
330
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
331
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
332
 
        self.assertWalkerNext(u'd', 'd-id', False, [u'd'], iterator)
333
 
        self.assertRaises(StopIteration, iterator.next)
334
 
 
335
 
    def test_others_extra_at_end(self):
336
 
        tree = self.make_branch_and_tree('tree')
337
 
        self.build_tree(['tree/a', 'tree/b', 'tree/c', 'tree/d', 'tree/e'])
338
 
        tree.add(['a', 'b', 'c', 'd', 'e'],
339
 
                 ['a-id', 'b-id', 'c-id', 'd-id', 'e-id'])
340
 
        tree.commit('first', rev_id='first-rev-id')
341
 
        tree.remove(['e'])
342
 
        tree.commit('second', rev_id='second-rev-id')
343
 
        tree.remove(['d'])
344
 
        tree.commit('third', rev_id='third-rev-id')
345
 
        tree.remove(['c'])
346
 
 
347
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
348
 
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
349
 
        second_tree = tree.branch.repository.revision_tree('second-rev-id')
350
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree,
351
 
                                              second_tree])
352
 
        iterator = walker.iter_all()
353
 
        self.assertWalkerNext(u'', root_id, True, [u'', u'', u''], iterator)
354
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a', u'a', u'a'], iterator)
355
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b', u'b', u'b'], iterator)
356
 
        self.assertWalkerNext(u'c', 'c-id', False, [u'c', u'c', u'c'], iterator)
357
 
        self.assertWalkerNext(u'd', 'd-id', False, [None, u'd', u'd'], iterator)
358
 
        self.assertWalkerNext(u'e', 'e-id', False, [None, u'e', None], iterator)
359
 
        self.assertRaises(StopIteration, iterator.next)
360
 
 
361
 
    def test_different_file_id_in_others(self):
362
 
        tree = self.make_branch_and_tree('tree')
363
 
        self.build_tree(['tree/a', 'tree/b', 'tree/c/'])
364
 
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
365
 
        tree.commit('first', rev_id='first-rev-id')
366
 
 
367
 
        tree.rename_one('b', 'c/d')
368
 
        self.build_tree(['tree/b'])
369
 
        tree.add(['b'], ['b2-id'])
370
 
        tree.commit('second', rev_id='second-rev-id')
371
 
 
372
 
        tree.rename_one('a', 'c/e')
373
 
        self.build_tree(['tree/a'])
374
 
        tree.add(['a'], ['a2-id'])
375
 
 
376
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
377
 
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
378
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree])
379
 
 
380
 
        iterator = walker.iter_all()
381
 
        self.assertWalkerNext(u'', root_id, True, [u'', u''], iterator)
382
 
        self.assertWalkerNext(u'a', 'a2-id', True, [None, None], iterator)
383
 
        self.assertWalkerNext(u'b', 'b2-id', True, [u'b', None], iterator)
384
 
        self.assertWalkerNext(u'c', 'c-id', True, [u'c', u'c'], iterator)
385
 
        self.assertWalkerNext(u'c/d', 'b-id', True, [u'c/d', u'b'], iterator)
386
 
        self.assertWalkerNext(u'c/e', 'a-id', True, [u'a', u'a'], iterator)
387
 
        self.assertRaises(StopIteration, iterator.next)
388
 
 
389
 
    def assertCmpByDirblock(self, cmp_val, path1, path2):
390
 
        self.assertEqual(cmp_val,
391
 
            _mod_tree.MultiWalker._cmp_path_by_dirblock(path1, path2))
392
 
 
393
 
    def test__cmp_path_by_dirblock(self):
394
 
        # We only support Unicode strings at this point
395
 
        self.assertRaises(TypeError,
396
 
            _mod_tree.MultiWalker._cmp_path_by_dirblock, '', 'b')
397
 
        self.assertCmpByDirblock(0, u'', u'')
398
 
        self.assertCmpByDirblock(0, u'a', u'a')
399
 
        self.assertCmpByDirblock(0, u'a/b', u'a/b')
400
 
        self.assertCmpByDirblock(0, u'a/b/c', u'a/b/c')
401
 
        self.assertCmpByDirblock(1, u'a-a', u'a')
402
 
        self.assertCmpByDirblock(-1, u'a-a', u'a/a')
403
 
        self.assertCmpByDirblock(-1, u'a=a', u'a/a')
404
 
        self.assertCmpByDirblock(1, u'a-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/a')
407
 
        self.assertCmpByDirblock(1, u'a=a/a', u'a/a/a')
408
 
        self.assertCmpByDirblock(1, u'a-a/a/a', u'a/a/a')
409
 
        self.assertCmpByDirblock(1, u'a=a/a/a', u'a/a/a')
410
 
 
411
 
    def assertPathToKey(self, expected, path):
412
 
        self.assertEqual(expected, _mod_tree.MultiWalker._path_to_key(path))
413
 
 
414
 
    def test__path_to_key(self):
415
 
        self.assertPathToKey(([u''], u''), u'')
416
 
        self.assertPathToKey(([u''], u'a'), u'a')
417
 
        self.assertPathToKey(([u'a'], u'b'), u'a/b')
418
 
        self.assertPathToKey(([u'a', u'b'], u'c'), u'a/b/c')