/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
"""Tests for WorkingTreeFormat4"""
19
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
20
import os
21
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
22
from bzrlib import (
23
    bzrdir,
24
    dirstate,
25
    errors,
26
    workingtree_4,
27
    )
28
from bzrlib.lockdir import LockDir
29
from bzrlib.tests import TestCaseWithTransport, TestSkipped
30
from bzrlib.tree import InterTree
31
32
33
class TestWorkingTreeFormat4(TestCaseWithTransport):
34
    """Tests specific to WorkingTreeFormat4."""
35
36
    def test_disk_layout(self):
37
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
38
        control.create_repository()
39
        control.create_branch()
40
        tree = workingtree_4.WorkingTreeFormat4().initialize(control)
41
        # we want:
42
        # format 'Bazaar Working Tree format 4'
43
        # stat-cache = ??
44
        t = control.get_workingtree_transport(None)
2255.2.230 by Robert Collins
Update tree format signatures to mention introducing bzr version.
45
        self.assertEqualDiff('Bazaar Working Tree Format 4 (bzr 0.15)\n',
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
46
                             t.get('format').read())
47
        self.assertFalse(t.has('inventory.basis'))
48
        # no last-revision file means 'None' or 'NULLREVISION'
49
        self.assertFalse(t.has('last-revision'))
50
        state = dirstate.DirState.on_file(t.local_abspath('dirstate'))
51
        state.lock_read()
52
        try:
53
            self.assertEqual([], state.get_parent_ids())
54
        finally:
55
            state.unlock()
56
57
    def test_uses_lockdir(self):
58
        """WorkingTreeFormat4 uses its own LockDir:
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
59
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
60
            - lock is a directory
61
            - when the WorkingTree is locked, LockDir can see that
62
        """
63
        # this test could be factored into a subclass of tests common to both
64
        # format 3 and 4, but for now its not much of an issue as there is only one in common.
65
        t = self.get_transport()
66
        tree = self.make_workingtree()
67
        self.assertIsDirectory('.bzr', t)
68
        self.assertIsDirectory('.bzr/checkout', t)
69
        self.assertIsDirectory('.bzr/checkout/lock', t)
70
        our_lock = LockDir(t, '.bzr/checkout/lock')
71
        self.assertEquals(our_lock.peek(), None)
72
        tree.lock_write()
73
        self.assertTrue(our_lock.peek())
74
        tree.unlock()
75
        self.assertEquals(our_lock.peek(), None)
76
77
    def make_workingtree(self, relpath=''):
78
        url = self.get_url(relpath)
79
        if relpath:
80
            self.build_tree([relpath + '/'])
81
        dir = bzrdir.BzrDirMetaFormat1().initialize(url)
82
        repo = dir.create_repository()
83
        branch = dir.create_branch()
84
        try:
85
            return workingtree_4.WorkingTreeFormat4().initialize(dir)
86
        except errors.NotLocalUrl:
87
            raise TestSkipped('Not a local URL')
88
89
    def test_dirstate_stores_all_parent_inventories(self):
90
        tree = self.make_workingtree()
91
92
        # We're going to build in tree a working tree 
93
        # with three parent trees, with some files in common.  
94
    
95
        # We really don't want to do commit or merge in the new dirstate-based
96
        # tree, because that might not work yet.  So instead we build
97
        # revisions elsewhere and pull them across, doing by hand part of the
98
        # work that merge would do.
99
100
        subtree = self.make_branch_and_tree('subdir')
101
        # writelock the tree so its repository doesn't get readlocked by
102
        # the revision tree locks. This works around the bug where we dont
103
        # permit lock upgrading.
104
        subtree.lock_write()
105
        self.addCleanup(subtree.unlock)
106
        self.build_tree(['subdir/file-a',])
107
        subtree.add(['file-a'], ['id-a'])
108
        rev1 = subtree.commit('commit in subdir')
109
110
        subtree2 = subtree.bzrdir.sprout('subdir2').open_workingtree()
111
        self.build_tree(['subdir2/file-b'])
112
        subtree2.add(['file-b'], ['id-b'])
113
        rev2 = subtree2.commit('commit in subdir2')
114
115
        subtree.flush()
116
        subtree.merge_from_branch(subtree2.branch)
117
        rev3 = subtree.commit('merge from subdir2')
118
119
        repo = tree.branch.repository
120
        repo.fetch(subtree.branch.repository, rev3)
121
        # will also pull the others...
122
123
        # create repository based revision trees
124
        rev1_revtree = subtree.branch.repository.revision_tree(rev1)
125
        rev2_revtree = subtree2.branch.repository.revision_tree(rev2)
126
        rev3_revtree = subtree.branch.repository.revision_tree(rev3)
127
        # tree doesn't contain a text merge yet but we'll just
128
        # set the parents as if a merge had taken place. 
129
        # this should cause the tree data to be folded into the 
130
        # dirstate.
131
        tree.set_parent_trees([
132
            (rev1, rev1_revtree),
133
            (rev2, rev2_revtree),
134
            (rev3, rev3_revtree), ])
135
136
        # create tree-sourced revision trees
137
        rev1_tree = tree.revision_tree(rev1)
138
        rev1_tree.lock_read()
139
        self.addCleanup(rev1_tree.unlock)
140
        rev2_tree = tree.revision_tree(rev2)
141
        rev2_tree.lock_read()
142
        self.addCleanup(rev2_tree.unlock)
143
        rev3_tree = tree.revision_tree(rev3)
144
        rev3_tree.lock_read()
145
        self.addCleanup(rev3_tree.unlock)
146
147
        # now we should be able to get them back out
148
        self.assertTreesEqual(rev1_revtree, rev1_tree)
149
        self.assertTreesEqual(rev2_revtree, rev2_tree)
150
        self.assertTreesEqual(rev3_revtree, rev3_tree)
151
152
    def test_dirstate_doesnt_read_parents_from_repo_when_setting(self):
153
        """Setting parent trees on a dirstate working tree takes
154
        the trees it's given and doesn't need to read them from the 
155
        repository.
156
        """
157
        tree = self.make_workingtree()
158
159
        subtree = self.make_branch_and_tree('subdir')
160
        rev1 = subtree.commit('commit in subdir')
161
        rev1_tree = subtree.basis_tree()
162
        rev1_tree.lock_read()
163
        self.addCleanup(rev1_tree.unlock)
164
165
        tree.branch.pull(subtree.branch)
166
167
        # break the repository's legs to make sure it only uses the trees
168
        # it's given; any calls to forbidden methods will raise an 
169
        # AssertionError
170
        repo = tree.branch.repository
171
        repo.get_revision = self.fail
172
        repo.get_inventory = self.fail
173
        repo.get_inventory_xml = self.fail
174
        # try to set the parent trees.
175
        tree.set_parent_trees([(rev1, rev1_tree)])
176
177
    def test_dirstate_doesnt_read_from_repo_when_returning_cache_tree(self):
178
        """Getting parent trees from a dirstate tree does not read from the 
179
        repos inventory store. This is an important part of the dirstate
180
        performance optimisation work.
181
        """
182
        tree = self.make_workingtree()
183
184
        subtree = self.make_branch_and_tree('subdir')
185
        # writelock the tree so its repository doesn't get readlocked by
186
        # the revision tree locks. This works around the bug where we dont
187
        # permit lock upgrading.
188
        subtree.lock_write()
189
        self.addCleanup(subtree.unlock)
190
        rev1 = subtree.commit('commit in subdir')
191
        rev1_tree = subtree.basis_tree()
192
        rev1_tree.lock_read()
193
        rev1_tree.inventory
194
        self.addCleanup(rev1_tree.unlock)
195
        rev2 = subtree.commit('second commit in subdir', allow_pointless=True)
196
        rev2_tree = subtree.basis_tree()
197
        rev2_tree.lock_read()
198
        rev2_tree.inventory
199
        self.addCleanup(rev2_tree.unlock)
200
201
        tree.branch.pull(subtree.branch)
202
203
        # break the repository's legs to make sure it only uses the trees
204
        # it's given; any calls to forbidden methods will raise an 
205
        # AssertionError
206
        repo = tree.branch.repository
207
        # dont uncomment this: the revision object must be accessed to 
208
        # answer 'get_parent_ids' for the revision tree- dirstate does not 
209
        # cache the parents of a parent tree at this point.
210
        #repo.get_revision = self.fail
211
        repo.get_inventory = self.fail
212
        repo.get_inventory_xml = self.fail
213
        # set the parent trees.
214
        tree.set_parent_trees([(rev1, rev1_tree), (rev2, rev2_tree)])
215
        # read the first tree
216
        result_rev1_tree = tree.revision_tree(rev1)
217
        # read the second
218
        result_rev2_tree = tree.revision_tree(rev2)
219
        # compare - there should be no differences between the handed and 
220
        # returned trees
221
        self.assertTreesEqual(rev1_tree, result_rev1_tree)
222
        self.assertTreesEqual(rev2_tree, result_rev2_tree)
223
224
    def test_dirstate_doesnt_cache_non_parent_trees(self):
225
        """Getting parent trees from a dirstate tree does not read from the 
226
        repos inventory store. This is an important part of the dirstate
227
        performance optimisation work.
228
        """
229
        tree = self.make_workingtree()
230
231
        # make a tree that we can try for, which is able to be returned but
232
        # must not be
233
        subtree = self.make_branch_and_tree('subdir')
234
        rev1 = subtree.commit('commit in subdir')
235
        tree.branch.pull(subtree.branch)
236
        # check it fails
237
        self.assertRaises(errors.NoSuchRevision, tree.revision_tree, rev1)
238
239
    def test_no_dirstate_outside_lock(self):
240
        # temporary test until the code is mature enough to test from outside.
241
        """Getting a dirstate object fails if there is no lock."""
242
        def lock_and_call_current_dirstate(tree, lock_method):
243
            getattr(tree, lock_method)()
244
            tree.current_dirstate()
245
            tree.unlock()
246
        tree = self.make_workingtree()
247
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
248
        lock_and_call_current_dirstate(tree, 'lock_read')
249
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
250
        lock_and_call_current_dirstate(tree, 'lock_write')
251
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
252
        lock_and_call_current_dirstate(tree, 'lock_tree_write')
253
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
254
255
    def test_new_dirstate_on_new_lock(self):
256
        # until we have detection for when a dirstate can be reused, we
257
        # want to reparse dirstate on every new lock.
258
        known_dirstates = set()
259
        def lock_and_compare_all_current_dirstate(tree, lock_method):
260
            getattr(tree, lock_method)()
261
            state = tree.current_dirstate()
262
            self.assertFalse(state in known_dirstates)
263
            known_dirstates.add(state)
264
            tree.unlock()
265
        tree = self.make_workingtree()
266
        # lock twice with each type to prevent silly per-lock-type bugs.
267
        # each lock and compare looks for a unique state object.
268
        lock_and_compare_all_current_dirstate(tree, 'lock_read')
269
        lock_and_compare_all_current_dirstate(tree, 'lock_read')
270
        lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
271
        lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
272
        lock_and_compare_all_current_dirstate(tree, 'lock_write')
273
        lock_and_compare_all_current_dirstate(tree, 'lock_write')
274
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
275
    def test_constructing_invalid_interdirstate_raises(self):
276
        tree = self.make_workingtree()
277
        rev_id = tree.commit('first post')
278
        rev_id2 = tree.commit('second post')
279
        rev_tree = tree.branch.repository.revision_tree(rev_id)
280
        # Exception is not a great thing to raise, but this test is 
281
        # very short, and code is used to sanity check other tests, so 
282
        # a full error object is YAGNI.
283
        self.assertRaises(
284
            Exception, workingtree_4.InterDirStateTree, rev_tree, tree)
285
        self.assertRaises(
286
            Exception, workingtree_4.InterDirStateTree, tree, rev_tree)
287
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
288
    def test_revtree_to_revtree_not_interdirstate(self):
289
        # we should not get a dirstate optimiser for two repository sourced
290
        # revtrees. we can't prove a negative, so we dont do exhaustive tests
291
        # of all formats; though that could be written in the future it doesn't
292
        # seem well worth it.
293
        tree = self.make_workingtree()
294
        rev_id = tree.commit('first post')
295
        rev_id2 = tree.commit('second post')
296
        rev_tree = tree.branch.repository.revision_tree(rev_id)
297
        rev_tree2 = tree.branch.repository.revision_tree(rev_id2)
298
        optimiser = InterTree.get(rev_tree, rev_tree2)
299
        self.assertIsInstance(optimiser, InterTree)
300
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
301
        optimiser = InterTree.get(rev_tree2, rev_tree)
302
        self.assertIsInstance(optimiser, InterTree)
303
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
304
305
    def test_revtree_not_in_dirstate_to_dirstate_not_interdirstate(self):
306
        # we should not get a dirstate optimiser when the revision id for of
307
        # the source is not in the dirstate of the target.
308
        tree = self.make_workingtree()
309
        rev_id = tree.commit('first post')
310
        rev_id2 = tree.commit('second post')
311
        rev_tree = tree.branch.repository.revision_tree(rev_id)
312
        tree.lock_read()
313
        optimiser = InterTree.get(rev_tree, tree)
314
        self.assertIsInstance(optimiser, InterTree)
315
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
316
        optimiser = InterTree.get(tree, rev_tree)
317
        self.assertIsInstance(optimiser, InterTree)
318
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
319
        tree.unlock()
320
321
    def test_empty_basis_to_dirstate_tree(self):
322
        # we should get a InterDirStateTree for doing
323
        # 'changes_from' from the first basis dirstate revision tree to a
324
        # WorkingTree4.
325
        tree = self.make_workingtree()
326
        tree.lock_read()
327
        basis_tree = tree.basis_tree()
328
        basis_tree.lock_read()
329
        optimiser = InterTree.get(basis_tree, tree)
330
        tree.unlock()
331
        basis_tree.unlock()
332
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
333
334
    def test_nonempty_basis_to_dirstate_tree(self):
335
        # we should get a InterDirStateTree for doing
336
        # 'changes_from' from a non-null basis dirstate revision tree to a
337
        # WorkingTree4.
338
        tree = self.make_workingtree()
339
        tree.commit('first post')
340
        tree.lock_read()
341
        basis_tree = tree.basis_tree()
342
        basis_tree.lock_read()
343
        optimiser = InterTree.get(basis_tree, tree)
344
        tree.unlock()
345
        basis_tree.unlock()
346
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
347
348
    def test_empty_basis_revtree_to_dirstate_tree(self):
349
        # we should get a InterDirStateTree for doing
350
        # 'changes_from' from an empty repository based rev tree to a
351
        # WorkingTree4.
352
        tree = self.make_workingtree()
353
        tree.lock_read()
354
        basis_tree = tree.branch.repository.revision_tree(tree.last_revision())
355
        basis_tree.lock_read()
356
        optimiser = InterTree.get(basis_tree, tree)
357
        tree.unlock()
358
        basis_tree.unlock()
359
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
360
361
    def test_nonempty_basis_revtree_to_dirstate_tree(self):
362
        # we should get a InterDirStateTree for doing
363
        # 'changes_from' from a non-null repository based rev tree to a
364
        # WorkingTree4.
365
        tree = self.make_workingtree()
366
        tree.commit('first post')
367
        tree.lock_read()
368
        basis_tree = tree.branch.repository.revision_tree(tree.last_revision())
369
        basis_tree.lock_read()
370
        optimiser = InterTree.get(basis_tree, tree)
371
        tree.unlock()
372
        basis_tree.unlock()
373
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
374
375
    def test_tree_to_basis_in_other_tree(self):
376
        # we should get a InterDirStateTree when
377
        # the source revid is in the dirstate object of the target and
378
        # the dirstates are different. This is largely covered by testing
379
        # with repository revtrees, so is just for extra confidence.
380
        tree = self.make_workingtree('a')
381
        tree.commit('first post')
382
        tree2 = self.make_workingtree('b')
383
        tree2.pull(tree.branch)
384
        basis_tree = tree.basis_tree()
385
        tree2.lock_read()
386
        basis_tree.lock_read()
387
        optimiser = InterTree.get(basis_tree, tree2)
388
        tree2.unlock()
389
        basis_tree.unlock()
390
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
391
392
    def test_merged_revtree_to_tree(self):
393
        # we should get a InterDirStateTree when
394
        # the source tree is a merged tree present in the dirstate of target.
395
        tree = self.make_workingtree('a')
396
        tree.commit('first post')
397
        tree.commit('tree 1 commit 2')
398
        tree2 = self.make_workingtree('b')
399
        tree2.pull(tree.branch)
400
        tree2.commit('tree 2 commit 2')
401
        tree.merge_from_branch(tree2.branch)
402
        second_parent_tree = tree.revision_tree(tree.get_parent_ids()[1])
403
        second_parent_tree.lock_read()
404
        tree.lock_read()
405
        optimiser = InterTree.get(second_parent_tree, tree)
406
        tree.unlock()
407
        second_parent_tree.unlock()
408
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
409
410
    def test_id2path(self):
411
        tree = self.make_workingtree('tree')
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
412
        self.build_tree(['tree/a', 'tree/b'])
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
413
        tree.add(['a'], ['a-id'])
414
        self.assertEqual(u'a', tree.id2path('a-id'))
2255.11.5 by Martin Pool
Tree.id2path should raise NoSuchId, not return None.
415
        self.assertRaises(errors.NoSuchId, tree.id2path, 'a')
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
416
        tree.commit('a')
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
417
        tree.add(['b'], ['b-id'])
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
418
2321.1.2 by Robert Collins
Skip new tests that depend on unicode file paths.
419
        try:
420
            tree.rename_one('a', u'b\xb5rry')
421
            new_path = u'b\xb5rry'
422
        except UnicodeEncodeError:
423
            # support running the test on non-unicode platforms
424
            tree.rename_one('a', 'c')
425
            new_path = 'c'
426
        self.assertEqual(new_path, tree.id2path('a-id'))
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
427
        tree.commit(u'b\xb5rry')
428
        tree.unversion(['a-id'])
2255.11.5 by Martin Pool
Tree.id2path should raise NoSuchId, not return None.
429
        self.assertRaises(errors.NoSuchId, tree.id2path, 'a-id')
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
430
        self.assertEqual('b', tree.id2path('b-id'))
2255.11.5 by Martin Pool
Tree.id2path should raise NoSuchId, not return None.
431
        self.assertRaises(errors.NoSuchId, tree.id2path, 'c-id')
2255.2.166 by Martin Pool
(broken) Add Tree.get_root_id() & test
432
433
    def test_unique_root_id_per_tree(self):
434
        # each time you initialize a new tree, it gets a different root id
2255.2.207 by Robert Collins
Reinstate format change for test_workingtree_4
435
        format_name = 'dirstate-with-subtree'
2255.2.166 by Martin Pool
(broken) Add Tree.get_root_id() & test
436
        tree1 = self.make_branch_and_tree('tree1',
437
            format=format_name)
438
        tree2 = self.make_branch_and_tree('tree2',
439
            format=format_name)
440
        self.assertNotEqual(tree1.get_root_id(), tree2.get_root_id())
441
        # when you branch, it inherits the same root id
442
        rev1 = tree1.commit('first post')
443
        tree3 = tree1.bzrdir.sprout('tree3').open_workingtree()
444
        self.assertEqual(tree3.get_root_id(), tree1.get_root_id())
445
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
446
    def test_set_root_id(self):
447
        # similar to some code that fails in the dirstate-plus-subtree branch
448
        # -- setting the root id while adding a parent seems to scramble the
449
        # dirstate invariants. -- mbp 20070303
450
        def validate():
451
            wt.lock_read()
452
            try:
453
                wt.current_dirstate()._validate()
454
            finally:
455
                wt.unlock()
456
        wt = self.make_workingtree('tree')
457
        wt.set_root_id('TREE-ROOTID')
458
        validate()
459
        wt.commit('somenthing')
460
        validate()
461
        # now switch and commit again
462
        wt.set_root_id('tree-rootid')
463
        validate()
464
        wt.commit('again')
465
        validate()
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
466
467
    def test_non_subtree_with_nested_trees(self):
468
        # prior to dirstate, st/diff/commit ignored nested trees.
469
        # dirstate, as opposed to dirstate-with-subtree, should
470
        # behave the same way.
471
        tree = self.make_branch_and_tree('.', format='dirstate')
472
        self.assertFalse(tree.supports_tree_reference())
473
        self.build_tree(['dir/'])
474
        # for testing easily.
475
        tree.set_root_id('root')
476
        tree.add(['dir'], ['dir-id'])
477
        subtree = self.make_branch_and_tree('dir')
478
        # the most primitive operation: kind
479
        self.assertEqual('directory', tree.kind('dir-id'))
480
        # a diff against the basis should give us a directory
481
        tree.lock_read()
482
        expected = [('dir-id',
483
            (None, u'dir'),
484
            True,
485
            (False, True),
486
            (None, 'root'),
487
            (None, u'dir'),
488
            (None, 'directory'),
489
            (None, False))]
490
        self.assertEqual(expected, list(tree._iter_changes(tree.basis_tree(),
491
            specific_files=['dir'])))
492
        tree.unlock()
493
        # do a commit, we want to trigger the dirstate fast-path too
494
        tree.commit('first post')
495
        # change the path for the subdir, which will trigger getting all
496
        # its data:
497
        os.rename('dir', 'also-dir')
498
        # now the diff will use the fast path
499
        tree.lock_read()
500
        expected = [('dir-id',
501
            (u'dir', u'dir'),
502
            True,
503
            (True, True),
504
            ('root', 'root'),
505
            ('dir', 'dir'),
506
            ('directory', None),
507
            (False, False))]
508
        self.assertEqual(expected, list(tree._iter_changes(tree.basis_tree())))
509
        tree.unlock()
510
511
    def test_with_subtree_supports_tree_references(self):
512
        # dirstate-with-subtree should support tree-references.
513
        tree = self.make_branch_and_tree('.', format='dirstate-with-subtree')
514
        self.assertTrue(tree.supports_tree_reference())
515
        # having checked this is on, the tree interface, and intertree
516
        # interface tests, will proceed to test the subtree support of
517
        # workingtree_4.