/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_tree.py

  • Committer: Jelmer Vernooij
  • Date: 2017-08-07 11:49:46 UTC
  • mto: (6747.3.4 avoid-set-revid-3)
  • mto: This revision was merged to the branch mainline in revision 6750.
  • Revision ID: jelmer@jelmer.uk-20170807114946-luclmxuawyzhpiot
Avoid setting revision_ids.

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