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