/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1
# Copyright (C) 2007-2012, 2016 Canonical Ltd
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
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
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
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
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
21
import time
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
22
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
23
from .. import (
6670.4.1 by Jelmer Vernooij
Update imports.
24
    errors,
25
    osutils,
26
    )
27
from ..bzr import (
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
28
    bzrdir,
29
    dirstate,
1551.15.6 by Aaron Bentley
Use ROOT_ID when the repository supports old clients (Bug #107168)
30
    inventory,
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
31
    workingtree_4,
32
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
33
from ..lockdir import LockDir
34
from . import TestCaseWithTransport, TestSkipped, features
35
from ..tree import InterTree
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
36
37
38
class TestWorkingTreeFormat4(TestCaseWithTransport):
39
    """Tests specific to WorkingTreeFormat4."""
40
41
    def test_disk_layout(self):
42
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
43
        control.create_repository()
44
        control.create_branch()
45
        tree = workingtree_4.WorkingTreeFormat4().initialize(control)
46
        # we want:
47
        # format 'Bazaar Working Tree format 4'
48
        # stat-cache = ??
49
        t = control.get_workingtree_transport(None)
2255.2.230 by Robert Collins
Update tree format signatures to mention introducing bzr version.
50
        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
51
                             t.get('format').read())
52
        self.assertFalse(t.has('inventory.basis'))
53
        # no last-revision file means 'None' or 'NULLREVISION'
54
        self.assertFalse(t.has('last-revision'))
55
        state = dirstate.DirState.on_file(t.local_abspath('dirstate'))
56
        state.lock_read()
57
        try:
58
            self.assertEqual([], state.get_parent_ids())
59
        finally:
60
            state.unlock()
61
5900.1.1 by Jelmer Vernooij
Make sure only the last unlock resets the cached ignore glob.
62
    def test_resets_ignores_on_last_unlock(self):
63
        # Only the last unlock call will actually reset the
64
        # ignores. (bug #785671)
65
        tree = self.make_workingtree()
66
        tree.lock_read()
67
        try:
68
            tree.lock_read()
69
            try:
70
                tree.is_ignored("foo")
71
            finally:
72
                tree.unlock()
73
            self.assertIsNot(None, tree._ignoreglobster)
74
        finally:
75
            tree.unlock()
76
        self.assertIs(None, tree._ignoreglobster)
77
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
78
    def test_uses_lockdir(self):
79
        """WorkingTreeFormat4 uses its own LockDir:
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
80
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
81
            - lock is a directory
82
            - when the WorkingTree is locked, LockDir can see that
83
        """
84
        # this test could be factored into a subclass of tests common to both
4285.2.1 by Vincent Ladeuil
Cleanup test imports and use features to better track skipped tests.
85
        # format 3 and 4, but for now its not much of an issue as there is only
86
        # one in common.
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
87
        t = self.get_transport()
88
        tree = self.make_workingtree()
89
        self.assertIsDirectory('.bzr', t)
90
        self.assertIsDirectory('.bzr/checkout', t)
91
        self.assertIsDirectory('.bzr/checkout/lock', t)
92
        our_lock = LockDir(t, '.bzr/checkout/lock')
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
93
        self.assertEqual(our_lock.peek(), None)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
94
        tree.lock_write()
95
        self.assertTrue(our_lock.peek())
96
        tree.unlock()
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
97
        self.assertEqual(our_lock.peek(), None)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
98
99
    def make_workingtree(self, relpath=''):
100
        url = self.get_url(relpath)
101
        if relpath:
102
            self.build_tree([relpath + '/'])
103
        dir = bzrdir.BzrDirMetaFormat1().initialize(url)
104
        repo = dir.create_repository()
105
        branch = dir.create_branch()
106
        try:
107
            return workingtree_4.WorkingTreeFormat4().initialize(dir)
108
        except errors.NotLocalUrl:
109
            raise TestSkipped('Not a local URL')
110
111
    def test_dirstate_stores_all_parent_inventories(self):
112
        tree = self.make_workingtree()
113
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
114
        # We're going to build in tree a working tree
115
        # with three parent trees, with some files in common.
116
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
117
        # We really don't want to do commit or merge in the new dirstate-based
118
        # tree, because that might not work yet.  So instead we build
119
        # revisions elsewhere and pull them across, doing by hand part of the
120
        # work that merge would do.
121
122
        subtree = self.make_branch_and_tree('subdir')
123
        # writelock the tree so its repository doesn't get readlocked by
124
        # the revision tree locks. This works around the bug where we dont
125
        # permit lock upgrading.
126
        subtree.lock_write()
127
        self.addCleanup(subtree.unlock)
128
        self.build_tree(['subdir/file-a',])
7007.1.9 by Jelmer Vernooij
Fix more dirstate tests.
129
        subtree.add(['file-a'], [b'id-a'])
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
130
        rev1 = subtree.commit('commit in subdir')
131
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
132
        subtree2 = subtree.controldir.sprout('subdir2').open_workingtree()
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
133
        self.build_tree(['subdir2/file-b'])
7007.1.9 by Jelmer Vernooij
Fix more dirstate tests.
134
        subtree2.add(['file-b'], [b'id-b'])
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
135
        rev2 = subtree2.commit('commit in subdir2')
136
137
        subtree.flush()
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
138
        subtree3 = subtree.controldir.sprout('subdir3').open_workingtree()
3462.1.7 by John Arbash Meinel
fix a test that assumed WT4.set_parent_trees() wouldn't filter the list.
139
        rev3 = subtree3.commit('merge from subdir2')
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
140
141
        repo = tree.branch.repository
3462.1.7 by John Arbash Meinel
fix a test that assumed WT4.set_parent_trees() wouldn't filter the list.
142
        repo.fetch(subtree.branch.repository, rev1)
143
        repo.fetch(subtree2.branch.repository, rev2)
144
        repo.fetch(subtree3.branch.repository, rev3)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
145
        # will also pull the others...
146
147
        # create repository based revision trees
3462.1.7 by John Arbash Meinel
fix a test that assumed WT4.set_parent_trees() wouldn't filter the list.
148
        rev1_revtree = repo.revision_tree(rev1)
149
        rev2_revtree = repo.revision_tree(rev2)
150
        rev3_revtree = repo.revision_tree(rev3)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
151
        # tree doesn't contain a text merge yet but we'll just
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
152
        # set the parents as if a merge had taken place.
153
        # this should cause the tree data to be folded into the
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
154
        # dirstate.
155
        tree.set_parent_trees([
156
            (rev1, rev1_revtree),
157
            (rev2, rev2_revtree),
158
            (rev3, rev3_revtree), ])
159
160
        # create tree-sourced revision trees
161
        rev1_tree = tree.revision_tree(rev1)
162
        rev1_tree.lock_read()
163
        self.addCleanup(rev1_tree.unlock)
164
        rev2_tree = tree.revision_tree(rev2)
165
        rev2_tree.lock_read()
166
        self.addCleanup(rev2_tree.unlock)
167
        rev3_tree = tree.revision_tree(rev3)
168
        rev3_tree.lock_read()
169
        self.addCleanup(rev3_tree.unlock)
170
171
        # now we should be able to get them back out
172
        self.assertTreesEqual(rev1_revtree, rev1_tree)
173
        self.assertTreesEqual(rev2_revtree, rev2_tree)
174
        self.assertTreesEqual(rev3_revtree, rev3_tree)
175
176
    def test_dirstate_doesnt_read_parents_from_repo_when_setting(self):
177
        """Setting parent trees on a dirstate working tree takes
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
178
        the trees it's given and doesn't need to read them from the
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
179
        repository.
180
        """
181
        tree = self.make_workingtree()
182
183
        subtree = self.make_branch_and_tree('subdir')
184
        rev1 = subtree.commit('commit in subdir')
185
        rev1_tree = subtree.basis_tree()
186
        rev1_tree.lock_read()
187
        self.addCleanup(rev1_tree.unlock)
188
189
        tree.branch.pull(subtree.branch)
190
191
        # break the repository's legs to make sure it only uses the trees
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
192
        # it's given; any calls to forbidden methods will raise an
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
193
        # AssertionError
194
        repo = tree.branch.repository
5340.15.1 by John Arbash Meinel
supersede exc-info branch
195
        self.overrideAttr(repo, "get_revision", self.fail)
196
        self.overrideAttr(repo, "get_inventory", self.fail)
197
        self.overrideAttr(repo, "_get_inventory_xml", self.fail)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
198
        # try to set the parent trees.
199
        tree.set_parent_trees([(rev1, rev1_tree)])
200
201
    def test_dirstate_doesnt_read_from_repo_when_returning_cache_tree(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
202
        """Getting parent trees from a dirstate tree does not read from the
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
203
        repos inventory store. This is an important part of the dirstate
204
        performance optimisation work.
205
        """
206
        tree = self.make_workingtree()
207
208
        subtree = self.make_branch_and_tree('subdir')
209
        # writelock the tree so its repository doesn't get readlocked by
210
        # the revision tree locks. This works around the bug where we dont
211
        # permit lock upgrading.
212
        subtree.lock_write()
213
        self.addCleanup(subtree.unlock)
214
        rev1 = subtree.commit('commit in subdir')
215
        rev1_tree = subtree.basis_tree()
216
        rev1_tree.lock_read()
6405.2.12 by Jelmer Vernooij
Fix tests.
217
        rev1_tree.root_inventory
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
218
        self.addCleanup(rev1_tree.unlock)
219
        rev2 = subtree.commit('second commit in subdir', allow_pointless=True)
220
        rev2_tree = subtree.basis_tree()
221
        rev2_tree.lock_read()
6405.2.12 by Jelmer Vernooij
Fix tests.
222
        rev2_tree.root_inventory
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
223
        self.addCleanup(rev2_tree.unlock)
224
225
        tree.branch.pull(subtree.branch)
226
227
        # break the repository's legs to make sure it only uses the trees
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
228
        # it's given; any calls to forbidden methods will raise an
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
229
        # AssertionError
230
        repo = tree.branch.repository
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
231
        # dont uncomment this: the revision object must be accessed to
232
        # answer 'get_parent_ids' for the revision tree- dirstate does not
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
233
        # cache the parents of a parent tree at this point.
234
        #repo.get_revision = self.fail
5340.15.1 by John Arbash Meinel
supersede exc-info branch
235
        self.overrideAttr(repo, "get_inventory", self.fail)
236
        self.overrideAttr(repo, "_get_inventory_xml", self.fail)
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
237
        # set the parent trees.
238
        tree.set_parent_trees([(rev1, rev1_tree), (rev2, rev2_tree)])
239
        # read the first tree
240
        result_rev1_tree = tree.revision_tree(rev1)
241
        # read the second
242
        result_rev2_tree = tree.revision_tree(rev2)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
243
        # compare - there should be no differences between the handed and
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
244
        # returned trees
245
        self.assertTreesEqual(rev1_tree, result_rev1_tree)
246
        self.assertTreesEqual(rev2_tree, result_rev2_tree)
247
248
    def test_dirstate_doesnt_cache_non_parent_trees(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
249
        """Getting parent trees from a dirstate tree does not read from the
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
250
        repos inventory store. This is an important part of the dirstate
251
        performance optimisation work.
252
        """
253
        tree = self.make_workingtree()
254
255
        # make a tree that we can try for, which is able to be returned but
256
        # must not be
257
        subtree = self.make_branch_and_tree('subdir')
258
        rev1 = subtree.commit('commit in subdir')
259
        tree.branch.pull(subtree.branch)
260
        # check it fails
261
        self.assertRaises(errors.NoSuchRevision, tree.revision_tree, rev1)
262
263
    def test_no_dirstate_outside_lock(self):
264
        # temporary test until the code is mature enough to test from outside.
265
        """Getting a dirstate object fails if there is no lock."""
266
        def lock_and_call_current_dirstate(tree, lock_method):
267
            getattr(tree, lock_method)()
268
            tree.current_dirstate()
269
            tree.unlock()
270
        tree = self.make_workingtree()
271
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
272
        lock_and_call_current_dirstate(tree, 'lock_read')
273
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
274
        lock_and_call_current_dirstate(tree, 'lock_write')
275
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
276
        lock_and_call_current_dirstate(tree, 'lock_tree_write')
277
        self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
278
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
279
    def test_set_parent_trees_uses_update_basis_by_delta(self):
280
        builder = self.make_branch_builder('source')
281
        builder.start_series()
282
        self.addCleanup(builder.finish_series)
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
283
        builder.build_snapshot([], [
6973.6.2 by Jelmer Vernooij
Fix more tests.
284
            ('add', ('', b'root-id', 'directory', None)),
285
            ('add', ('a', b'a-id', 'file', b'content\n'))],
6973.5.2 by Jelmer Vernooij
Add more bees.
286
            revision_id=b'A')
6973.6.2 by Jelmer Vernooij
Fix more tests.
287
        builder.build_snapshot([b'A'], [
288
            ('modify', ('a', b'new content\nfor a\n')),
289
            ('add', ('b', b'b-id', 'file', b'b-content\n'))],
6973.5.2 by Jelmer Vernooij
Add more bees.
290
            revision_id=b'B')
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
291
        tree = self.make_workingtree('tree')
292
        source_branch = builder.get_branch()
6973.6.2 by Jelmer Vernooij
Fix more tests.
293
        tree.branch.repository.fetch(source_branch.repository, b'B')
294
        tree.pull(source_branch, stop_revision=b'A')
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
295
        tree.lock_write()
296
        self.addCleanup(tree.unlock)
297
        state = tree.current_dirstate()
298
        called = []
299
        orig_update = state.update_basis_by_delta
300
        def log_update_basis_by_delta(delta, new_revid):
301
            called.append(new_revid)
302
            return orig_update(delta, new_revid)
303
        state.update_basis_by_delta = log_update_basis_by_delta
304
        basis = tree.basis_tree()
6973.6.2 by Jelmer Vernooij
Fix more tests.
305
        self.assertEqual(b'a-id', basis.path2id('a'))
6852.3.1 by Jelmer Vernooij
add Tree.is_versioned.
306
        self.assertFalse(basis.is_versioned('b'))
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
307
        def fail_set_parent_trees(trees, ghosts):
308
            raise AssertionError('dirstate.set_parent_trees() was called')
309
        state.set_parent_trees = fail_set_parent_trees
310
        repo = tree.branch.repository
6973.6.2 by Jelmer Vernooij
Fix more tests.
311
        tree.pull(source_branch, stop_revision=b'B')
312
        self.assertEqual([b'B'], called)
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
313
        basis = tree.basis_tree()
6973.6.2 by Jelmer Vernooij
Fix more tests.
314
        self.assertEqual(b'a-id', basis.path2id('a'))
315
        self.assertEqual(b'b-id', basis.path2id('b'))
5847.4.1 by John Arbash Meinel
When WT4.set_parent_trees() is called, sometimes we can use
316
5847.4.10 by John Arbash Meinel
A few more bug fixes.
317
    def test_set_parent_trees_handles_missing_basis(self):
318
        builder = self.make_branch_builder('source')
319
        builder.start_series()
320
        self.addCleanup(builder.finish_series)
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
321
        builder.build_snapshot([], [
6973.6.2 by Jelmer Vernooij
Fix more tests.
322
            ('add', ('', b'root-id', 'directory', None)),
323
            ('add', ('a', b'a-id', 'file', b'content\n'))],
6973.5.2 by Jelmer Vernooij
Add more bees.
324
            revision_id=b'A')
6973.6.2 by Jelmer Vernooij
Fix more tests.
325
        builder.build_snapshot([b'A'], [
326
            ('modify', ('a', b'new content\nfor a\n')),
327
            ('add', ('b', b'b-id', 'file', b'b-content\n'))],
6973.5.2 by Jelmer Vernooij
Add more bees.
328
            revision_id=b'B')
6973.6.2 by Jelmer Vernooij
Fix more tests.
329
        builder.build_snapshot([b'A'], [
330
            ('add', ('c', b'c-id', 'file', b'c-content\n'))],
6973.5.2 by Jelmer Vernooij
Add more bees.
331
            revision_id=b'C')
5847.4.10 by John Arbash Meinel
A few more bug fixes.
332
        b_c = self.make_branch('branch_with_c')
6973.6.2 by Jelmer Vernooij
Fix more tests.
333
        b_c.pull(builder.get_branch(), stop_revision=b'C')
5847.4.10 by John Arbash Meinel
A few more bug fixes.
334
        b_b = self.make_branch('branch_with_b')
6973.6.2 by Jelmer Vernooij
Fix more tests.
335
        b_b.pull(builder.get_branch(), stop_revision=b'B')
5847.4.10 by John Arbash Meinel
A few more bug fixes.
336
        # This is reproducing some of what 'switch' does, just to isolate the
337
        # set_parent_trees() step.
338
        wt = b_b.create_checkout('tree', lightweight=True)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
339
        fmt = wt.controldir.find_branch_format()
340
        fmt.set_reference(wt.controldir, None, b_c)
5847.4.10 by John Arbash Meinel
A few more bug fixes.
341
        # Re-open with the new reference
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
342
        wt = wt.controldir.open_workingtree()
6973.6.2 by Jelmer Vernooij
Fix more tests.
343
        wt.set_parent_trees([(b'C', b_c.repository.revision_tree(b'C'))])
6852.3.1 by Jelmer Vernooij
add Tree.is_versioned.
344
        self.assertFalse(wt.basis_tree().is_versioned('b'))
5847.4.10 by John Arbash Meinel
A few more bug fixes.
345
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
346
    def test_new_dirstate_on_new_lock(self):
347
        # until we have detection for when a dirstate can be reused, we
348
        # want to reparse dirstate on every new lock.
349
        known_dirstates = set()
350
        def lock_and_compare_all_current_dirstate(tree, lock_method):
351
            getattr(tree, lock_method)()
352
            state = tree.current_dirstate()
353
            self.assertFalse(state in known_dirstates)
354
            known_dirstates.add(state)
355
            tree.unlock()
356
        tree = self.make_workingtree()
357
        # lock twice with each type to prevent silly per-lock-type bugs.
358
        # each lock and compare looks for a unique state object.
359
        lock_and_compare_all_current_dirstate(tree, 'lock_read')
360
        lock_and_compare_all_current_dirstate(tree, 'lock_read')
361
        lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
362
        lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
363
        lock_and_compare_all_current_dirstate(tree, 'lock_write')
364
        lock_and_compare_all_current_dirstate(tree, 'lock_write')
365
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
366
    def test_constructing_invalid_interdirstate_raises(self):
367
        tree = self.make_workingtree()
368
        rev_id = tree.commit('first post')
369
        rev_id2 = tree.commit('second post')
370
        rev_tree = tree.branch.repository.revision_tree(rev_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
371
        # Exception is not a great thing to raise, but this test is
372
        # very short, and code is used to sanity check other tests, so
2255.2.122 by Robert Collins
Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
373
        # a full error object is YAGNI.
374
        self.assertRaises(
375
            Exception, workingtree_4.InterDirStateTree, rev_tree, tree)
376
        self.assertRaises(
377
            Exception, workingtree_4.InterDirStateTree, tree, rev_tree)
378
2255.2.121 by John Arbash Meinel
split out the WorkingTreeFormat4 tests into a separate test file
379
    def test_revtree_to_revtree_not_interdirstate(self):
380
        # we should not get a dirstate optimiser for two repository sourced
381
        # revtrees. we can't prove a negative, so we dont do exhaustive tests
382
        # of all formats; though that could be written in the future it doesn't
383
        # seem well worth it.
384
        tree = self.make_workingtree()
385
        rev_id = tree.commit('first post')
386
        rev_id2 = tree.commit('second post')
387
        rev_tree = tree.branch.repository.revision_tree(rev_id)
388
        rev_tree2 = tree.branch.repository.revision_tree(rev_id2)
389
        optimiser = InterTree.get(rev_tree, rev_tree2)
390
        self.assertIsInstance(optimiser, InterTree)
391
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
392
        optimiser = InterTree.get(rev_tree2, rev_tree)
393
        self.assertIsInstance(optimiser, InterTree)
394
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
395
396
    def test_revtree_not_in_dirstate_to_dirstate_not_interdirstate(self):
397
        # we should not get a dirstate optimiser when the revision id for of
398
        # the source is not in the dirstate of the target.
399
        tree = self.make_workingtree()
400
        rev_id = tree.commit('first post')
401
        rev_id2 = tree.commit('second post')
402
        rev_tree = tree.branch.repository.revision_tree(rev_id)
403
        tree.lock_read()
404
        optimiser = InterTree.get(rev_tree, tree)
405
        self.assertIsInstance(optimiser, InterTree)
406
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
407
        optimiser = InterTree.get(tree, rev_tree)
408
        self.assertIsInstance(optimiser, InterTree)
409
        self.assertFalse(isinstance(optimiser, workingtree_4.InterDirStateTree))
410
        tree.unlock()
411
412
    def test_empty_basis_to_dirstate_tree(self):
413
        # we should get a InterDirStateTree for doing
414
        # 'changes_from' from the first basis dirstate revision tree to a
415
        # WorkingTree4.
416
        tree = self.make_workingtree()
417
        tree.lock_read()
418
        basis_tree = tree.basis_tree()
419
        basis_tree.lock_read()
420
        optimiser = InterTree.get(basis_tree, tree)
421
        tree.unlock()
422
        basis_tree.unlock()
423
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
424
425
    def test_nonempty_basis_to_dirstate_tree(self):
426
        # we should get a InterDirStateTree for doing
427
        # 'changes_from' from a non-null basis dirstate revision tree to a
428
        # WorkingTree4.
429
        tree = self.make_workingtree()
430
        tree.commit('first post')
431
        tree.lock_read()
432
        basis_tree = tree.basis_tree()
433
        basis_tree.lock_read()
434
        optimiser = InterTree.get(basis_tree, tree)
435
        tree.unlock()
436
        basis_tree.unlock()
437
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
438
439
    def test_empty_basis_revtree_to_dirstate_tree(self):
440
        # we should get a InterDirStateTree for doing
441
        # 'changes_from' from an empty repository based rev tree to a
442
        # WorkingTree4.
443
        tree = self.make_workingtree()
444
        tree.lock_read()
445
        basis_tree = tree.branch.repository.revision_tree(tree.last_revision())
446
        basis_tree.lock_read()
447
        optimiser = InterTree.get(basis_tree, tree)
448
        tree.unlock()
449
        basis_tree.unlock()
450
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
451
452
    def test_nonempty_basis_revtree_to_dirstate_tree(self):
453
        # we should get a InterDirStateTree for doing
454
        # 'changes_from' from a non-null repository based rev tree to a
455
        # WorkingTree4.
456
        tree = self.make_workingtree()
457
        tree.commit('first post')
458
        tree.lock_read()
459
        basis_tree = tree.branch.repository.revision_tree(tree.last_revision())
460
        basis_tree.lock_read()
461
        optimiser = InterTree.get(basis_tree, tree)
462
        tree.unlock()
463
        basis_tree.unlock()
464
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
465
466
    def test_tree_to_basis_in_other_tree(self):
467
        # we should get a InterDirStateTree when
468
        # the source revid is in the dirstate object of the target and
469
        # the dirstates are different. This is largely covered by testing
470
        # with repository revtrees, so is just for extra confidence.
471
        tree = self.make_workingtree('a')
472
        tree.commit('first post')
473
        tree2 = self.make_workingtree('b')
474
        tree2.pull(tree.branch)
475
        basis_tree = tree.basis_tree()
476
        tree2.lock_read()
477
        basis_tree.lock_read()
478
        optimiser = InterTree.get(basis_tree, tree2)
479
        tree2.unlock()
480
        basis_tree.unlock()
481
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
482
483
    def test_merged_revtree_to_tree(self):
484
        # we should get a InterDirStateTree when
485
        # the source tree is a merged tree present in the dirstate of target.
486
        tree = self.make_workingtree('a')
487
        tree.commit('first post')
488
        tree.commit('tree 1 commit 2')
489
        tree2 = self.make_workingtree('b')
490
        tree2.pull(tree.branch)
491
        tree2.commit('tree 2 commit 2')
492
        tree.merge_from_branch(tree2.branch)
493
        second_parent_tree = tree.revision_tree(tree.get_parent_ids()[1])
494
        second_parent_tree.lock_read()
495
        tree.lock_read()
496
        optimiser = InterTree.get(second_parent_tree, tree)
497
        tree.unlock()
498
        second_parent_tree.unlock()
499
        self.assertIsInstance(optimiser, workingtree_4.InterDirStateTree)
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
500
501
    def test_id2path(self):
502
        tree = self.make_workingtree('tree')
2255.2.147 by John Arbash Meinel
Move fast id => path lookups down into DirState
503
        self.build_tree(['tree/a', 'tree/b'])
6855.4.1 by Jelmer Vernooij
Yet more bees.
504
        tree.add(['a'], [b'a-id'])
505
        self.assertEqual(u'a', tree.id2path(b'a-id'))
2255.11.5 by Martin Pool
Tree.id2path should raise NoSuchId, not return None.
506
        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
507
        tree.commit('a')
6855.4.1 by Jelmer Vernooij
Yet more bees.
508
        tree.add(['b'], [b'b-id'])
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
509
2321.1.2 by Robert Collins
Skip new tests that depend on unicode file paths.
510
        try:
2825.6.1 by Robert Collins
* ``WorkingTree.rename_one`` will now raise an error if normalisation of the
511
            new_path = u'b\u03bcrry'
512
            tree.rename_one('a', new_path)
2321.1.2 by Robert Collins
Skip new tests that depend on unicode file paths.
513
        except UnicodeEncodeError:
514
            # support running the test on non-unicode platforms
515
            new_path = 'c'
2825.6.1 by Robert Collins
* ``WorkingTree.rename_one`` will now raise an error if normalisation of the
516
            tree.rename_one('a', new_path)
6855.4.1 by Jelmer Vernooij
Yet more bees.
517
        self.assertEqual(new_path, tree.id2path(b'a-id'))
2255.2.144 by John Arbash Meinel
Simplify update_minimal a bit more, by making id_index a
518
        tree.commit(u'b\xb5rry')
6809.4.25 by Jelmer Vernooij
Add paths argument to .unversion.
519
        tree.unversion([new_path])
6855.4.1 by Jelmer Vernooij
Yet more bees.
520
        self.assertRaises(errors.NoSuchId, tree.id2path, b'a-id')
521
        self.assertEqual('b', tree.id2path(b'b-id'))
522
        self.assertRaises(errors.NoSuchId, tree.id2path, b'c-id')
2255.2.166 by Martin Pool
(broken) Add Tree.get_root_id() & test
523
524
    def test_unique_root_id_per_tree(self):
525
        # each time you initialize a new tree, it gets a different root id
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
526
        format_name = 'development-subtree'
2255.2.166 by Martin Pool
(broken) Add Tree.get_root_id() & test
527
        tree1 = self.make_branch_and_tree('tree1',
528
            format=format_name)
529
        tree2 = self.make_branch_and_tree('tree2',
530
            format=format_name)
531
        self.assertNotEqual(tree1.get_root_id(), tree2.get_root_id())
532
        # when you branch, it inherits the same root id
533
        rev1 = tree1.commit('first post')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
534
        tree3 = tree1.controldir.sprout('tree3').open_workingtree()
2255.2.166 by Martin Pool
(broken) Add Tree.get_root_id() & test
535
        self.assertEqual(tree3.get_root_id(), tree1.get_root_id())
536
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
537
    def test_set_root_id(self):
538
        # similar to some code that fails in the dirstate-plus-subtree branch
539
        # -- setting the root id while adding a parent seems to scramble the
540
        # dirstate invariants. -- mbp 20070303
541
        def validate():
542
            wt.lock_read()
543
            try:
544
                wt.current_dirstate()._validate()
545
            finally:
546
                wt.unlock()
547
        wt = self.make_workingtree('tree')
6855.4.1 by Jelmer Vernooij
Yet more bees.
548
        wt.set_root_id(b'TREE-ROOTID')
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
549
        validate()
550
        wt.commit('somenthing')
551
        validate()
552
        # now switch and commit again
6855.4.1 by Jelmer Vernooij
Yet more bees.
553
        wt.set_root_id(b'tree-rootid')
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
554
        validate()
555
        wt.commit('again')
556
        validate()
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
557
1551.15.6 by Aaron Bentley
Use ROOT_ID when the repository supports old clients (Bug #107168)
558
    def test_default_root_id(self):
559
        tree = self.make_branch_and_tree('tag', format='dirstate-tags')
560
        self.assertEqual(inventory.ROOT_ID, tree.get_root_id())
561
        tree = self.make_branch_and_tree('subtree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
562
                                         format='development-subtree')
1551.15.6 by Aaron Bentley
Use ROOT_ID when the repository supports old clients (Bug #107168)
563
        self.assertNotEqual(inventory.ROOT_ID, tree.get_root_id())
564
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
565
    def test_non_subtree_with_nested_trees(self):
566
        # prior to dirstate, st/diff/commit ignored nested trees.
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
567
        # dirstate, as opposed to development-subtree, should
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
568
        # behave the same way.
569
        tree = self.make_branch_and_tree('.', format='dirstate')
570
        self.assertFalse(tree.supports_tree_reference())
571
        self.build_tree(['dir/'])
572
        # for testing easily.
6855.4.1 by Jelmer Vernooij
Yet more bees.
573
        tree.set_root_id(b'root')
574
        tree.add(['dir'], [b'dir-id'])
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
575
        subtree = self.make_branch_and_tree('dir')
576
        # the most primitive operation: kind
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
577
        self.assertEqual('directory', tree.kind('dir'))
4570.2.8 by Robert Collins
Adjust WorkingTree4 specific test to deal with iter_changes reporting required directories.
578
        # a diff against the basis should give us a directory and the root (as
579
        # the root is new too).
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
580
        tree.lock_read()
6973.13.2 by Jelmer Vernooij
Fix some more tests.
581
        expected = [(b'dir-id',
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
582
            (None, u'dir'),
583
            True,
584
            (False, True),
585
            (None, 'root'),
586
            (None, u'dir'),
587
            (None, 'directory'),
4570.2.8 by Robert Collins
Adjust WorkingTree4 specific test to deal with iter_changes reporting required directories.
588
            (None, False)),
589
            ('root', (None, u''), True, (False, True), (None, None),
590
            (None, u''), (None, 'directory'), (None, 0))]
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
591
        self.assertEqual(expected, list(tree.iter_changes(tree.basis_tree(),
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
592
            specific_files=['dir'])))
593
        tree.unlock()
594
        # do a commit, we want to trigger the dirstate fast-path too
595
        tree.commit('first post')
596
        # change the path for the subdir, which will trigger getting all
597
        # its data:
598
        os.rename('dir', 'also-dir')
599
        # now the diff will use the fast path
600
        tree.lock_read()
6973.13.2 by Jelmer Vernooij
Fix some more tests.
601
        expected = [(b'dir-id',
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
602
            (u'dir', u'dir'),
603
            True,
604
            (True, True),
605
            ('root', 'root'),
606
            ('dir', 'dir'),
607
            ('directory', None),
608
            (False, False))]
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
609
        self.assertEqual(expected, list(tree.iter_changes(tree.basis_tree())))
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
610
        tree.unlock()
611
612
    def test_with_subtree_supports_tree_references(self):
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
613
        # development-subtree should support tree-references.
614
        tree = self.make_branch_and_tree('.', format='development-subtree')
2255.2.232 by Robert Collins
Make WorkingTree4 report support for references based on the repositories capabilities.
615
        self.assertTrue(tree.supports_tree_reference())
616
        # having checked this is on, the tree interface, and intertree
617
        # interface tests, will proceed to test the subtree support of
618
        # workingtree_4.
2466.4.1 by John Arbash Meinel
Add a (failing) test that exposes how _iter_changes is accidentally walking into unversioned directories.
619
620
    def test_iter_changes_ignores_unversioned_dirs(self):
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
621
        """iter_changes should not descend into unversioned directories."""
2466.4.1 by John Arbash Meinel
Add a (failing) test that exposes how _iter_changes is accidentally walking into unversioned directories.
622
        tree = self.make_branch_and_tree('.', format='dirstate')
623
        # We have an unversioned directory at the root, a versioned one with
624
        # other versioned files and an unversioned directory, and another
625
        # versioned dir with nothing but an unversioned directory.
626
        self.build_tree(['unversioned/',
627
                         'unversioned/a',
628
                         'unversioned/b/',
629
                         'versioned/',
630
                         'versioned/unversioned/',
631
                         'versioned/unversioned/a',
632
                         'versioned/unversioned/b/',
633
                         'versioned2/',
634
                         'versioned2/a',
635
                         'versioned2/unversioned/',
636
                         'versioned2/unversioned/a',
637
                         'versioned2/unversioned/b/',
638
                        ])
639
        tree.add(['versioned', 'versioned2', 'versioned2/a'])
6855.4.1 by Jelmer Vernooij
Yet more bees.
640
        tree.commit('one', rev_id=b'rev-1')
2466.4.1 by John Arbash Meinel
Add a (failing) test that exposes how _iter_changes is accidentally walking into unversioned directories.
641
        # Trap osutils._walkdirs_utf8 to spy on what dirs have been accessed.
642
        returned = []
643
        def walkdirs_spy(*args, **kwargs):
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
644
            for val in orig(*args, **kwargs):
2466.4.1 by John Arbash Meinel
Add a (failing) test that exposes how _iter_changes is accidentally walking into unversioned directories.
645
                returned.append(val[0][0])
646
                yield val
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
647
        orig = self.overrideAttr(osutils, '_walkdirs_utf8', walkdirs_spy)
2466.4.1 by John Arbash Meinel
Add a (failing) test that exposes how _iter_changes is accidentally walking into unversioned directories.
648
649
        basis = tree.basis_tree()
650
        tree.lock_read()
651
        self.addCleanup(tree.unlock)
652
        basis.lock_read()
653
        self.addCleanup(basis.unlock)
2466.4.2 by John Arbash Meinel
Clean up the (failing) test so that the last thing
654
        changes = [c[1] for c in
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
655
                   tree.iter_changes(basis, want_unversioned=True)]
2466.4.2 by John Arbash Meinel
Clean up the (failing) test so that the last thing
656
        self.assertEqual([(None, 'unversioned'),
657
                          (None, 'versioned/unversioned'),
658
                          (None, 'versioned2/unversioned'),
659
                         ], changes)
660
        self.assertEqual(['', 'versioned', 'versioned2'], returned)
661
        del returned[:] # reset
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
662
        changes = [c[1] for c in tree.iter_changes(basis)]
2466.4.2 by John Arbash Meinel
Clean up the (failing) test so that the last thing
663
        self.assertEqual([], changes)
664
        self.assertEqual(['', 'versioned', 'versioned2'], returned)
3207.2.1 by jameinel
Add a test that _iter_changes raises a clearer error when we encounter an invalid rename.
665
4496.2.1 by Ian Clatworthy
(igc) Improve paths are not versioned reporting (Benoît PIERRE)
666
    def test_iter_changes_unversioned_error(self):
667
        """ Check if a PathsNotVersionedError is correctly raised and the
668
            paths list contains all unversioned entries only.
669
        """
670
        tree = self.make_branch_and_tree('tree')
6855.4.1 by Jelmer Vernooij
Yet more bees.
671
        self.build_tree_contents([('tree/bar', b'')])
672
        tree.add(['bar'], [b'bar-id'])
4496.2.1 by Ian Clatworthy
(igc) Improve paths are not versioned reporting (Benoît PIERRE)
673
        tree.lock_read()
674
        self.addCleanup(tree.unlock)
675
        tree_iter_changes = lambda files: [
676
            c for c in tree.iter_changes(tree.basis_tree(), specific_files=files,
677
                                         require_versioned=True)
678
        ]
679
        e = self.assertRaises(errors.PathsNotVersionedError,
680
                              tree_iter_changes, ['bar', 'foo'])
681
        self.assertEqual(e.paths, ['foo'])
682
6345.1.2 by Martin Packman
Add targetted working tree tests for places that raise PathsNotVersionedError
683
    def test_iter_changes_unversioned_non_ascii(self):
684
        """Unversioned non-ascii paths should be reported as unicode"""
685
        self.requireFeature(features.UnicodeFilenameFeature)
686
        tree = self.make_branch_and_tree('.')
6855.4.1 by Jelmer Vernooij
Yet more bees.
687
        self.build_tree_contents([('f', b'')])
688
        tree.add(['f'], [b'f-id'])
6345.1.2 by Martin Packman
Add targetted working tree tests for places that raise PathsNotVersionedError
689
        def tree_iter_changes(tree, files):
690
            return list(tree.iter_changes(tree.basis_tree(),
691
                specific_files=files, require_versioned=True))
692
        tree.lock_read()
693
        self.addCleanup(tree.unlock)
694
        e = self.assertRaises(errors.PathsNotVersionedError,
695
            tree_iter_changes, tree, [u'\xa7', u'\u03c0'])
6973.10.6 by Jelmer Vernooij
Fix tests.
696
        self.assertEqual(set(e.paths), set([u'\xa7', u'\u03c0']))
6345.1.2 by Martin Packman
Add targetted working tree tests for places that raise PathsNotVersionedError
697
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
698
    def get_tree_with_cachable_file_foo(self):
699
        tree = self.make_branch_and_tree('.')
5755.1.1 by John Arbash Meinel
Change WT._observed_sha1 to also update st.st_size.
700
        tree.lock_write()
701
        self.addCleanup(tree.unlock)
6855.4.1 by Jelmer Vernooij
Yet more bees.
702
        self.build_tree_contents([('foo', b'a bit of content for foo\n')])
703
        tree.add(['foo'], [b'foo-id'])
5755.1.1 by John Arbash Meinel
Change WT._observed_sha1 to also update st.st_size.
704
        tree.current_dirstate()._cutoff_time = time.time() + 60
3207.2.1 by jameinel
Add a test that _iter_changes raises a clearer error when we encounter an invalid rename.
705
        return tree
706
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
707
    def test_commit_updates_hash_cache(self):
708
        tree = self.get_tree_with_cachable_file_foo()
709
        revid = tree.commit('a commit')
710
        # tree's dirstate should now have a valid stat entry for foo.
711
        entry = tree._get_entry(path='foo')
712
        expected_sha1 = osutils.sha_file_by_name('foo')
713
        self.assertEqual(expected_sha1, entry[1][0][1])
5755.1.2 by John Arbash Meinel
use soft constants rather than '25'
714
        self.assertEqual(len('a bit of content for foo\n'), entry[1][0][2])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
715
716
    def test_observed_sha1_cachable(self):
717
        tree = self.get_tree_with_cachable_file_foo()
718
        expected_sha1 = osutils.sha_file_by_name('foo')
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
719
        statvalue = os.lstat("foo")
5755.1.1 by John Arbash Meinel
Change WT._observed_sha1 to also update st.st_size.
720
        tree._observed_sha1("foo-id", "foo", (expected_sha1, statvalue))
721
        entry = tree._get_entry(path="foo")
722
        entry_state = entry[1][0]
723
        self.assertEqual(expected_sha1, entry_state[1])
5755.1.2 by John Arbash Meinel
use soft constants rather than '25'
724
        self.assertEqual(statvalue.st_size, entry_state[2])
5755.1.1 by John Arbash Meinel
Change WT._observed_sha1 to also update st.st_size.
725
        tree.unlock()
726
        tree.lock_read()
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
727
        tree = tree.controldir.open_workingtree()
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
728
        tree.lock_read()
3207.2.1 by jameinel
Add a test that _iter_changes raises a clearer error when we encounter an invalid rename.
729
        self.addCleanup(tree.unlock)
5755.1.1 by John Arbash Meinel
Change WT._observed_sha1 to also update st.st_size.
730
        entry = tree._get_entry(path="foo")
731
        entry_state = entry[1][0]
732
        self.assertEqual(expected_sha1, entry_state[1])
5755.1.2 by John Arbash Meinel
use soft constants rather than '25'
733
        self.assertEqual(statvalue.st_size, entry_state[2])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
734
735
    def test_observed_sha1_new_file(self):
736
        tree = self.make_branch_and_tree('.')
737
        self.build_tree(['foo'])
6855.4.1 by Jelmer Vernooij
Yet more bees.
738
        tree.add(['foo'], [b'foo-id'])
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
739
        with tree.lock_read():
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
740
            current_sha1 = tree._get_entry(path="foo")[1][0][1]
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
741
        with tree.lock_write():
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
742
            tree._observed_sha1("foo-id", "foo",
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
743
                (osutils.sha_file_by_name('foo'), os.lstat("foo")))
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
744
            # Must not have changed
745
            self.assertEqual(current_sha1,
746
                tree._get_entry(path="foo")[1][0][1])
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
747
748
    def test_get_file_with_stat_id_only(self):
749
        # Explicit test to ensure we get a lstat value from WT4 trees.
750
        tree = self.make_branch_and_tree('.')
751
        self.build_tree(['foo'])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
752
        tree.add(['foo'])
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
753
        tree.lock_read()
754
        self.addCleanup(tree.unlock)
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
755
        file_obj, statvalue = tree.get_file_with_stat('foo')
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
756
        expected = os.lstat('foo')
4807.2.2 by John Arbash Meinel
Move all the stat comparison and platform checkning code to assertEqualStat.
757
        self.assertEqualStat(expected, statvalue)
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
758
        self.assertEqual(["contents of foo\n"], file_obj.readlines())
759
760
761
class TestCorruptDirstate(TestCaseWithTransport):
762
    """Tests for how we handle when the dirstate has been corrupted."""
763
764
    def create_wt4(self):
765
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
766
        control.create_repository()
767
        control.create_branch()
768
        tree = workingtree_4.WorkingTreeFormat4().initialize(control)
769
        return tree
770
771
    def test_invalid_rename(self):
772
        tree = self.create_wt4()
773
        # Create a corrupted dirstate
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
774
        with tree.lock_write():
4285.2.1 by Vincent Ladeuil
Cleanup test imports and use features to better track skipped tests.
775
            # We need a parent, or we always compare with NULL
776
            tree.commit('init')
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
777
            state = tree.current_dirstate()
778
            state._read_dirblocks_if_needed()
779
            # Now add in an invalid entry, a rename with a dangling pointer
6973.13.2 by Jelmer Vernooij
Fix some more tests.
780
            state._dirblocks[1][1].append((('', 'foo', b'foo-id'),
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
781
                                            [('f', '', 0, False, ''),
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
782
                                             ('r', 'bar', 0, False, '')]))
6744 by Jelmer Vernooij
Merge lp:~jelmer/brz/move-errors-knit.
783
            self.assertListRaises(dirstate.DirstateCorrupt,
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
784
                                  tree.iter_changes, tree.basis_tree())
785
786
    def get_simple_dirblocks(self, state):
787
        """Extract the simple information from the DirState.
788
789
        This returns the dirblocks, only with the sha1sum and stat details
790
        filtered out.
791
        """
792
        simple_blocks = []
793
        for block in state._dirblocks:
794
            simple_block = (block[0], [])
795
            for entry in block[1]:
796
                # Include the key for each entry, and for each parent include
797
                # just the minikind, so we know if it was
798
                # present/absent/renamed/etc
799
                simple_block[1].append((entry[0], [i[0] for i in entry[1]]))
800
            simple_blocks.append(simple_block)
801
        return simple_blocks
802
803
    def test_update_basis_with_invalid_delta(self):
804
        """When given an invalid delta, it should abort, and not be saved."""
805
        self.build_tree(['dir/', 'dir/file'])
806
        tree = self.create_wt4()
807
        tree.lock_write()
808
        self.addCleanup(tree.unlock)
6855.4.1 by Jelmer Vernooij
Yet more bees.
809
        tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
810
        first_revision_id = tree.commit('init')
811
812
        root_id = tree.path2id('')
813
        state = tree.current_dirstate()
814
        state._read_dirblocks_if_needed()
815
        self.assertEqual([
816
            ('', [(('', '', root_id), ['d', 'd'])]),
6855.4.1 by Jelmer Vernooij
Yet more bees.
817
            ('', [(('', 'dir', b'dir-id'), ['d', 'd'])]),
818
            ('dir', [(('dir', 'file', b'file-id'), ['f', 'f'])]),
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
819
        ],  self.get_simple_dirblocks(state))
820
821
        tree.remove(['dir/file'])
822
        self.assertEqual([
823
            ('', [(('', '', root_id), ['d', 'd'])]),
6855.4.1 by Jelmer Vernooij
Yet more bees.
824
            ('', [(('', 'dir', b'dir-id'), ['d', 'd'])]),
825
            ('dir', [(('dir', 'file', b'file-id'), ['a', 'f'])]),
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
826
        ],  self.get_simple_dirblocks(state))
827
        # Make sure the removal is written to disk
828
        tree.flush()
829
830
        # self.assertRaises(Exception, tree.update_basis_by_delta,
6855.4.1 by Jelmer Vernooij
Yet more bees.
831
        new_dir = inventory.InventoryDirectory(b'dir-id', 'new-dir', root_id)
832
        new_dir.revision = b'new-revision-id'
833
        new_file = inventory.InventoryFile(b'file-id', 'new-file', root_id)
834
        new_file.revision = b'new-revision-id'
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
835
        self.assertRaises(errors.InconsistentDelta,
6855.4.1 by Jelmer Vernooij
Yet more bees.
836
            tree.update_basis_by_delta, b'new-revision-id',
837
            [('dir', 'new-dir', b'dir-id', new_dir),
838
             ('dir/file', 'new-dir/new-file', b'file-id', new_file),
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
839
            ])
840
        del state
841
842
        # Now when we re-read the file it should not have been modified
843
        tree.unlock()
844
        tree.lock_read()
845
        self.assertEqual(first_revision_id, tree.last_revision())
846
        state = tree.current_dirstate()
847
        state._read_dirblocks_if_needed()
848
        self.assertEqual([
849
            ('', [(('', '', root_id), ['d', 'd'])]),
6855.4.1 by Jelmer Vernooij
Yet more bees.
850
            ('', [(('', 'dir', b'dir-id'), ['d', 'd'])]),
851
            ('dir', [(('dir', 'file', b'file-id'), ['a', 'f'])]),
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
852
        ],  self.get_simple_dirblocks(state))
4634.156.1 by Vincent Ladeuil
Don't traceback when unversioning a directory.
853
854
855
class TestInventoryCoherency(TestCaseWithTransport):
856
857
    def test_inventory_is_synced_when_unversioning_a_dir(self):
858
        """Unversioning the root of a subtree unversions the entire subtree."""
859
        tree = self.make_branch_and_tree('.')
860
        self.build_tree(['a/', 'a/b', 'c/'])
6855.4.1 by Jelmer Vernooij
Yet more bees.
861
        tree.add(['a', 'a/b', 'c'], [b'a-id', b'b-id', b'c-id'])
4634.156.1 by Vincent Ladeuil
Don't traceback when unversioning a directory.
862
        # within a lock unversion should take effect
863
        tree.lock_write()
864
        self.addCleanup(tree.unlock)
865
        # Force access to the in memory inventory to trigger bug #494221: try
866
        # maintaining the in-memory inventory
6405.2.10 by Jelmer Vernooij
Fix more tests.
867
        inv = tree.root_inventory
6973.7.5 by Jelmer Vernooij
s/file/open.
868
        self.assertTrue(inv.has_id(b'a-id'))
869
        self.assertTrue(inv.has_id(b'b-id'))
6809.4.25 by Jelmer Vernooij
Add paths argument to .unversion.
870
        tree.unversion(['a', 'a/b'])
6973.7.5 by Jelmer Vernooij
s/file/open.
871
        self.assertFalse(inv.has_id(b'a-id'))
872
        self.assertFalse(inv.has_id(b'b-id'))