~bzr-pqm/bzr/bzr.dev

5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2006-2011 Canonical Ltd
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
16
17
"""Tests of the dirstate functionality being built for WorkingTreeFormat4."""
18
1852.13.20 by Robert Collins
Steps toward an object model.
19
import os
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
20
import tempfile
1852.13.20 by Robert Collins
Steps toward an object model.
21
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
22
from bzrlib import (
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
23
    bzrdir,
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
24
    dirstate,
25
    errors,
3477.2.1 by John Arbash Meinel
Assert that we properly encode inv_entry.symlink_target, (bug #135320)
26
    inventory,
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
27
    memorytree,
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
28
    osutils,
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
29
    revision as _mod_revision,
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
30
    revisiontree,
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
31
    tests,
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
32
    workingtree_4,
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
33
    )
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
34
from bzrlib.transport import memory
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
35
from bzrlib.tests import (
36
    features,
37
    test_osutils,
38
    )
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
39
from bzrlib.tests.scenarios import load_tests_apply_scenarios
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
40
41
42
# TODO:
2255.2.4 by Robert Collins
Snapshot dirstate development
43
# TESTS to write:
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
44
# general checks for NOT_IN_MEMORY error conditions.
45
# set_path_id on a NOT_IN_MEMORY dirstate
2255.2.4 by Robert Collins
Snapshot dirstate development
46
# set_path_id  unicode support
47
# set_path_id  setting id of a path not root
48
# set_path_id  setting id when there are parents without the id in the parents
49
# set_path_id  setting id when there are parents with the id in the parents
50
# set_path_id  setting id when state is not in memory
51
# set_path_id  setting id when state is in memory unmodified
52
# set_path_id  setting id when state is in memory modified
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
53
2255.2.236 by Martin Pool
Review cleanups: mostly updating or removing todo comments.
54
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
55
load_tests = load_tests_apply_scenarios
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
56
57
58
class TestCaseWithDirState(tests.TestCaseWithTransport):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
59
    """Helper functions for creating DirState objects with various content."""
60
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
61
    scenarios = test_osutils.dir_reader_scenarios()
62
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
63
    # Set by load_tests
64
    _dir_reader_class = None
65
    _native_to_unicode = None # Not used yet
66
67
    def setUp(self):
68
        tests.TestCaseWithTransport.setUp(self)
69
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
70
        self.overrideAttr(osutils,
71
                          '_selected_dir_reader', self._dir_reader_class())
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
72
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
73
    def create_empty_dirstate(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
74
        """Return a locked but empty dirstate"""
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
75
        state = dirstate.DirState.initialize('dirstate')
76
        return state
77
78
    def create_dirstate_with_root(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
79
        """Return a write-locked state with a single root entry."""
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
80
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
81
        root_entry_direntry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
82
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
83
            ]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
84
        dirblocks = []
85
        dirblocks.append(('', [root_entry_direntry]))
86
        dirblocks.append(('', []))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
87
        state = self.create_empty_dirstate()
88
        try:
89
            state._set_data([], dirblocks)
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
90
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
91
        except:
92
            state.unlock()
93
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
94
        return state
95
96
    def create_dirstate_with_root_and_subdir(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
97
        """Return a locked DirState with a root and a subdir"""
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
98
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
99
        subdir_entry = ('', 'subdir', 'subdir-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
100
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
101
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
102
        state = self.create_dirstate_with_root()
103
        try:
104
            dirblocks = list(state._dirblocks)
105
            dirblocks[1][1].append(subdir_entry)
106
            state._set_data([], dirblocks)
107
        except:
108
            state.unlock()
109
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
110
        return state
111
112
    def create_complex_dirstate(self):
113
        """This dirstate contains multiple files and directories.
114
115
         /        a-root-value
116
         a/       a-dir
117
         b/       b-dir
118
         c        c-file
119
         d        d-file
120
         a/e/     e-dir
121
         a/f      f-file
122
         b/g      g-file
123
         b/h\xc3\xa5  h-\xc3\xa5-file  #This is u'\xe5' encoded into utf-8
124
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
125
        Notice that a/e is an empty directory.
126
127
        :return: The dirstate, still write-locked.
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
128
        """
129
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
130
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
131
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
132
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
133
            ]
134
        a_entry = ('', 'a', 'a-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
135
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
136
            ]
137
        b_entry = ('', 'b', 'b-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
138
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
139
            ]
140
        c_entry = ('', 'c', 'c-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
141
            ('f', null_sha, 10, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
142
            ]
143
        d_entry = ('', 'd', 'd-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
144
            ('f', null_sha, 20, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
145
            ]
146
        e_entry = ('a', 'e', 'e-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
147
            ('d', '', 0, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
148
            ]
149
        f_entry = ('a', 'f', 'f-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
150
            ('f', null_sha, 30, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
151
            ]
152
        g_entry = ('b', 'g', 'g-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
153
            ('f', null_sha, 30, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
154
            ]
155
        h_entry = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
156
            ('f', null_sha, 40, False, packed_stat),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
157
            ]
158
        dirblocks = []
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
159
        dirblocks.append(('', [root_entry]))
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
160
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
161
        dirblocks.append(('a', [e_entry, f_entry]))
162
        dirblocks.append(('b', [g_entry, h_entry]))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
163
        state = dirstate.DirState.initialize('dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
164
        state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
165
        try:
166
            state._set_data([], dirblocks)
167
        except:
168
            state.unlock()
169
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
170
        return state
171
172
    def check_state_with_reopen(self, expected_result, state):
173
        """Check that state has current state expected_result.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
174
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
175
        This will check the current state, open the file anew and check it
176
        again.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
177
        This function expects the current state to be locked for writing, and
178
        will unlock it before re-opening.
179
        This is required because we can't open a lock_read() while something
180
        else has a lock_write().
181
            write => mutually exclusive lock
182
            read => shared lock
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
183
        """
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
184
        # The state should already be write locked, since we just had to do
185
        # some operation to get here.
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
186
        self.assertTrue(state._lock_token is not None)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
187
        try:
188
            self.assertEqual(expected_result[0],  state.get_parent_ids())
189
            # there should be no ghosts in this tree.
190
            self.assertEqual([], state.get_ghosts())
191
            # there should be one fileid in this tree - the root of the tree.
192
            self.assertEqual(expected_result[1], list(state._iter_entries()))
193
            state.save()
194
        finally:
195
            state.unlock()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
196
        del state
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
197
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
198
        state.lock_read()
199
        try:
200
            self.assertEqual(expected_result[1], list(state._iter_entries()))
201
        finally:
202
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
203
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
204
    def create_basic_dirstate(self):
205
        """Create a dirstate with a few files and directories.
206
207
            a
208
            b/
209
              c
210
              d/
211
                e
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
212
            b-c
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
213
            f
214
        """
215
        tree = self.make_branch_and_tree('tree')
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
216
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'b-c', 'f']
217
        file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'b-c-id', 'f-id']
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
218
        self.build_tree(['tree/' + p for p in paths])
219
        tree.set_root_id('TREE_ROOT')
220
        tree.add([p.rstrip('/') for p in paths], file_ids)
221
        tree.commit('initial', rev_id='rev-1')
222
        revision_id = 'rev-1'
223
        # a_packed_stat = dirstate.pack_stat(os.stat('tree/a'))
2520.3.1 by Vincent Ladeuil
Fix 110448 by adding a relpath parameter to get_transport.
224
        t = self.get_transport('tree')
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
225
        a_text = t.get_bytes('a')
226
        a_sha = osutils.sha_string(a_text)
227
        a_len = len(a_text)
228
        # b_packed_stat = dirstate.pack_stat(os.stat('tree/b'))
229
        # c_packed_stat = dirstate.pack_stat(os.stat('tree/b/c'))
230
        c_text = t.get_bytes('b/c')
231
        c_sha = osutils.sha_string(c_text)
232
        c_len = len(c_text)
233
        # d_packed_stat = dirstate.pack_stat(os.stat('tree/b/d'))
234
        # e_packed_stat = dirstate.pack_stat(os.stat('tree/b/d/e'))
235
        e_text = t.get_bytes('b/d/e')
236
        e_sha = osutils.sha_string(e_text)
237
        e_len = len(e_text)
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
238
        b_c_text = t.get_bytes('b-c')
239
        b_c_sha = osutils.sha_string(b_c_text)
240
        b_c_len = len(b_c_text)
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
241
        # f_packed_stat = dirstate.pack_stat(os.stat('tree/f'))
242
        f_text = t.get_bytes('f')
243
        f_sha = osutils.sha_string(f_text)
244
        f_len = len(f_text)
245
        null_stat = dirstate.DirState.NULLSTAT
246
        expected = {
247
            '':(('', '', 'TREE_ROOT'), [
248
                  ('d', '', 0, False, null_stat),
249
                  ('d', '', 0, False, revision_id),
250
                ]),
251
            'a':(('', 'a', 'a-id'), [
252
                   ('f', '', 0, False, null_stat),
253
                   ('f', a_sha, a_len, False, revision_id),
254
                 ]),
255
            'b':(('', 'b', 'b-id'), [
256
                  ('d', '', 0, False, null_stat),
257
                  ('d', '', 0, False, revision_id),
258
                 ]),
259
            'b/c':(('b', 'c', 'c-id'), [
260
                    ('f', '', 0, False, null_stat),
261
                    ('f', c_sha, c_len, False, revision_id),
262
                   ]),
263
            'b/d':(('b', 'd', 'd-id'), [
264
                    ('d', '', 0, False, null_stat),
265
                    ('d', '', 0, False, revision_id),
266
                   ]),
267
            'b/d/e':(('b/d', 'e', 'e-id'), [
268
                      ('f', '', 0, False, null_stat),
269
                      ('f', e_sha, e_len, False, revision_id),
270
                     ]),
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
271
            'b-c':(('', 'b-c', 'b-c-id'), [
272
                      ('f', '', 0, False, null_stat),
273
                      ('f', b_c_sha, b_c_len, False, revision_id),
274
                     ]),
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
275
            'f':(('', 'f', 'f-id'), [
276
                  ('f', '', 0, False, null_stat),
277
                  ('f', f_sha, f_len, False, revision_id),
278
                 ]),
279
        }
280
        state = dirstate.DirState.from_tree(tree, 'dirstate')
281
        try:
282
            state.save()
283
        finally:
284
            state.unlock()
285
        # Use a different object, to make sure nothing is pre-cached in memory.
286
        state = dirstate.DirState.on_file('dirstate')
287
        state.lock_read()
288
        self.addCleanup(state.unlock)
289
        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
290
                         state._dirblock_state)
291
        # This is code is only really tested if we actually have to make more
292
        # than one read, so set the page size to something smaller.
293
        # We want it to contain about 2.2 records, so that we have a couple
294
        # records that we can read per attempt
295
        state._bisect_page_size = 200
296
        return tree, state, expected
297
298
    def create_duplicated_dirstate(self):
299
        """Create a dirstate with a deleted and added entries.
300
301
        This grabs a basic_dirstate, and then removes and re adds every entry
302
        with a new file id.
303
        """
304
        tree, state, expected = self.create_basic_dirstate()
305
        # Now we will just remove and add every file so we get an extra entry
306
        # per entry. Unversion in reverse order so we handle subdirs
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
307
        tree.unversion(['f-id', 'b-c-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
308
        tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f'],
309
                 ['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'b-c-id2', 'f-id2'])
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
310
311
        # Update the expected dictionary.
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
312
        for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f']:
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
313
            orig = expected[path]
314
            path2 = path + '2'
315
            # This record was deleted in the current tree
316
            expected[path] = (orig[0], [dirstate.DirState.NULL_PARENT_DETAILS,
317
                                        orig[1][1]])
318
            new_key = (orig[0][0], orig[0][1], orig[0][2]+'2')
319
            # And didn't exist in the basis tree
320
            expected[path2] = (new_key, [orig[1][0],
321
                                         dirstate.DirState.NULL_PARENT_DETAILS])
322
323
        # We will replace the 'dirstate' file underneath 'state', but that is
324
        # okay as lock as we unlock 'state' first.
325
        state.unlock()
326
        try:
327
            new_state = dirstate.DirState.from_tree(tree, 'dirstate')
328
            try:
329
                new_state.save()
330
            finally:
331
                new_state.unlock()
332
        finally:
333
            # But we need to leave state in a read-lock because we already have
334
            # a cleanup scheduled
335
            state.lock_read()
336
        return tree, state, expected
337
338
    def create_renamed_dirstate(self):
339
        """Create a dirstate with a few internal renames.
340
341
        This takes the basic dirstate, and moves the paths around.
342
        """
343
        tree, state, expected = self.create_basic_dirstate()
344
        # Rename a file
345
        tree.rename_one('a', 'b/g')
346
        # And a directory
347
        tree.rename_one('b/d', 'h')
348
349
        old_a = expected['a']
350
        expected['a'] = (old_a[0], [('r', 'b/g', 0, False, ''), old_a[1][1]])
351
        expected['b/g'] = (('b', 'g', 'a-id'), [old_a[1][0],
352
                                                ('r', 'a', 0, False, '')])
353
        old_d = expected['b/d']
354
        expected['b/d'] = (old_d[0], [('r', 'h', 0, False, ''), old_d[1][1]])
355
        expected['h'] = (('', 'h', 'd-id'), [old_d[1][0],
356
                                             ('r', 'b/d', 0, False, '')])
357
358
        old_e = expected['b/d/e']
359
        expected['b/d/e'] = (old_e[0], [('r', 'h/e', 0, False, ''),
360
                             old_e[1][1]])
361
        expected['h/e'] = (('h', 'e', 'e-id'), [old_e[1][0],
362
                                                ('r', 'b/d/e', 0, False, '')])
363
364
        state.unlock()
365
        try:
366
            new_state = dirstate.DirState.from_tree(tree, 'dirstate')
367
            try:
368
                new_state.save()
369
            finally:
370
                new_state.unlock()
371
        finally:
372
            state.lock_read()
373
        return tree, state, expected
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
374
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
375
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
376
class TestTreeToDirState(TestCaseWithDirState):
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
377
378
    def test_empty_to_dirstate(self):
379
        """We should be able to create a dirstate for an empty tree."""
380
        # There are no files on disk and no parents
381
        tree = self.make_branch_and_tree('tree')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
382
        expected_result = ([], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
383
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
384
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
385
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
386
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
387
        state._validate()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
388
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
389
390
    def test_1_parents_empty_to_dirstate(self):
391
        # create a parent by doing a commit
392
        tree = self.make_branch_and_tree('tree')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
393
        rev_id = tree.commit('first post').encode('utf8')
394
        root_stat_pack = dirstate.pack_stat(os.stat(tree.basedir))
395
        expected_result = ([rev_id], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
396
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
397
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
398
              ('d', '', 0, False, rev_id), # first parent details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
399
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
400
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
401
        self.check_state_with_reopen(expected_result, state)
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
402
        state.lock_read()
403
        try:
404
            state._validate()
405
        finally:
406
            state.unlock()
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
407
408
    def test_2_parents_empty_to_dirstate(self):
409
        # create a parent by doing a commit
410
        tree = self.make_branch_and_tree('tree')
411
        rev_id = tree.commit('first post')
412
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
413
        rev_id2 = tree2.commit('second post', allow_pointless=True)
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
414
        tree.merge_from_branch(tree2.branch)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
415
        expected_result = ([rev_id, rev_id2], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
416
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
417
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
418
              ('d', '', 0, False, rev_id), # first parent details
4599.4.24 by Robert Collins
Prepare dirstate tests for 2a as default.
419
              ('d', '', 0, False, rev_id), # second parent details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
420
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
421
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
422
        self.check_state_with_reopen(expected_result, state)
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
423
        state.lock_read()
424
        try:
425
            state._validate()
426
        finally:
427
            state.unlock()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
428
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
429
    def test_empty_unknowns_are_ignored_to_dirstate(self):
430
        """We should be able to create a dirstate for an empty tree."""
431
        # There are no files on disk and no parents
432
        tree = self.make_branch_and_tree('tree')
1852.13.10 by Robert Collins
Use just the tree api to generate dirstate information.
433
        self.build_tree(['tree/unknown'])
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
434
        expected_result = ([], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
435
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
436
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
437
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
438
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
439
        self.check_state_with_reopen(expected_result, state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
440
1852.13.12 by Robert Collins
get actual parent info for the first parent.
441
    def get_tree_with_a_file(self):
442
        tree = self.make_branch_and_tree('tree')
443
        self.build_tree(['tree/a file'])
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
444
        tree.add('a file', 'a-file-id')
1852.13.12 by Robert Collins
get actual parent info for the first parent.
445
        return tree
446
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
447
    def test_non_empty_no_parents_to_dirstate(self):
448
        """We should be able to create a dirstate for an empty tree."""
1852.13.11 by Robert Collins
Get one content containing test passing.
449
        # There are files on disk and no parents
1852.13.12 by Robert Collins
get actual parent info for the first parent.
450
        tree = self.get_tree_with_a_file()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
451
        expected_result = ([], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
452
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
453
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
454
             ]),
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
455
            (('', 'a file', 'a-file-id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
456
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
457
             ]),
458
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
459
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
460
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
461
462
    def test_1_parents_not_empty_to_dirstate(self):
463
        # create a parent by doing a commit
1852.13.12 by Robert Collins
get actual parent info for the first parent.
464
        tree = self.get_tree_with_a_file()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
465
        rev_id = tree.commit('first post').encode('utf8')
1852.13.12 by Robert Collins
get actual parent info for the first parent.
466
        # change the current content to be different this will alter stat, sha
467
        # and length:
468
        self.build_tree_contents([('tree/a file', 'new content\n')])
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
469
        expected_result = ([rev_id], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
470
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
471
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
472
              ('d', '', 0, False, rev_id), # first parent details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
473
             ]),
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
474
            (('', 'a file', 'a-file-id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
475
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
476
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
477
               rev_id), # first parent
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
478
             ]),
479
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
480
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
481
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
482
483
    def test_2_parents_not_empty_to_dirstate(self):
484
        # create a parent by doing a commit
1852.13.13 by Robert Collins
2-parent case working.
485
        tree = self.get_tree_with_a_file()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
486
        rev_id = tree.commit('first post').encode('utf8')
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
487
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
1852.13.13 by Robert Collins
2-parent case working.
488
        # change the current content to be different this will alter stat, sha
489
        # and length:
490
        self.build_tree_contents([('tree2/a file', 'merge content\n')])
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
491
        rev_id2 = tree2.commit('second post').encode('utf8')
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
492
        tree.merge_from_branch(tree2.branch)
1852.13.13 by Robert Collins
2-parent case working.
493
        # change the current content to be different this will alter stat, sha
494
        # and length again, giving us three distinct values:
495
        self.build_tree_contents([('tree/a file', 'new content\n')])
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
496
        expected_result = ([rev_id, rev_id2], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
497
            (('', '', tree.get_root_id()), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
498
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
499
              ('d', '', 0, False, rev_id), # first parent details
4599.4.24 by Robert Collins
Prepare dirstate tests for 2a as default.
500
              ('d', '', 0, False, rev_id), # second parent details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
501
             ]),
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
502
            (('', 'a file', 'a-file-id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
503
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
504
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
505
               rev_id), # first parent
506
              ('f', '314d796174c9412647c3ce07dfb5d36a94e72958', 14, False,
507
               rev_id2), # second parent
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
508
             ]),
509
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
510
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
511
        self.check_state_with_reopen(expected_result, state)
512
2255.7.94 by Martin Pool
Fix dirstate sorting bug and refine the _validate() assertions:
513
    def test_colliding_fileids(self):
514
        # test insertion of parents creating several entries at the same path.
515
        # we used to have a bug where they could cause the dirstate to break
516
        # its ordering invariants.
517
        # create some trees to test from
518
        parents = []
519
        for i in range(7):
520
            tree = self.make_branch_and_tree('tree%d' % i)
521
            self.build_tree(['tree%d/name' % i,])
522
            tree.add(['name'], ['file-id%d' % i])
523
            revision_id = 'revid-%d' % i
524
            tree.commit('message', rev_id=revision_id)
525
            parents.append((revision_id,
526
                tree.branch.repository.revision_tree(revision_id)))
527
        # now fold these trees into a dirstate
528
        state = dirstate.DirState.initialize('dirstate')
529
        try:
530
            state.set_parent_trees(parents, [])
531
            state._validate()
532
        finally:
533
            state.unlock()
534
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
535
536
class TestDirStateOnFile(TestCaseWithDirState):
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
537
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
538
    def create_updated_dirstate(self):
539
        self.build_tree(['a-file'])
540
        tree = self.make_branch_and_tree('.')
541
        tree.add(['a-file'], ['a-id'])
542
        tree.commit('add a-file')
543
        # Save and unlock the state, re-open it in readonly mode
544
        state = dirstate.DirState.from_tree(tree, 'dirstate')
545
        state.save()
546
        state.unlock()
547
        state = dirstate.DirState.on_file('dirstate')
548
        state.lock_read()
549
        return state
550
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
551
    def test_construct_with_path(self):
552
        tree = self.make_branch_and_tree('tree')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
553
        state = dirstate.DirState.from_tree(tree, 'dirstate.from_tree')
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
554
        # we want to be able to get the lines of the dirstate that we will
555
        # write to disk.
556
        lines = state.get_lines()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
557
        state.unlock()
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
558
        self.build_tree_contents([('dirstate', ''.join(lines))])
559
        # get a state object
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
560
        # no parents, default tree content
561
        expected_result = ([], [
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
562
            (('', '', tree.get_root_id()), # common details
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
563
             # current tree details, but new from_tree skips statting, it
564
             # uses set_state_from_inventory, and thus depends on the
565
             # inventory state.
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
566
             [('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
567
             ])
568
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
569
        state = dirstate.DirState.on_file('dirstate')
570
        state.lock_write() # check_state_with_reopen will save() and unlock it
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
571
        self.check_state_with_reopen(expected_result, state)
572
573
    def test_can_save_clean_on_file(self):
574
        tree = self.make_branch_and_tree('tree')
575
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
576
        try:
577
            # doing a save should work here as there have been no changes.
578
            state.save()
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
579
            # TODO: stat it and check it hasn't changed; may require waiting
580
            # for the state accuracy window.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
581
        finally:
582
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
583
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
584
    def test_can_save_in_read_lock(self):
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
585
        state = self.create_updated_dirstate()
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
586
        try:
587
            entry = state._get_entry(0, path_utf8='a-file')
3709.4.1 by Robert Collins
Sha files for the stat cache more lazily rather than on first-examination, allowing less overall sha calculations to occur.
588
            # The current size should be 0 (default)
589
            self.assertEqual(0, entry[1][0][2])
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
590
            # We should have a real entry.
591
            self.assertNotEqual((None, None), entry)
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
592
            # Set the cutoff-time into the future, so things look cacheable
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
593
            state._sha_cutoff_time()
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
594
            state._cutoff_time += 10.0
595
            st = os.lstat('a-file')
596
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
597
            # We updated the current sha1sum because the file is cacheable
598
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
599
                             sha1sum)
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
600
601
            # The dirblock has been updated
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
602
            self.assertEqual(st.st_size, entry[1][0][2])
5807.4.3 by John Arbash Meinel
Get the test suite to run clean for bt.test_dirstate bt.test__dirstate bt.test_workingtree
603
            self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
604
                             state._dirblock_state)
605
606
            del entry
607
            # Now, since we are the only one holding a lock, we should be able
608
            # to save and have it written to disk
609
            state.save()
610
        finally:
611
            state.unlock()
612
613
        # Re-open the file, and ensure that the state has been updated.
614
        state = dirstate.DirState.on_file('dirstate')
615
        state.lock_read()
616
        try:
617
            entry = state._get_entry(0, path_utf8='a-file')
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
618
            self.assertEqual(st.st_size, entry[1][0][2])
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
619
        finally:
620
            state.unlock()
621
622
    def test_save_fails_quietly_if_locked(self):
623
        """If dirstate is locked, save will fail without complaining."""
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
624
        state = self.create_updated_dirstate()
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
625
        try:
626
            entry = state._get_entry(0, path_utf8='a-file')
5802.3.2 by John Arbash Meinel
We have to update some tests, because what used to be IN_MEMORY_MODIFIED isn't.
627
            # No cached sha1 yet.
628
            self.assertEqual('', entry[1][0][1])
629
            # Set the cutoff-time into the future, so things look cacheable
630
            state._sha_cutoff_time()
631
            state._cutoff_time += 10.0
632
            st = os.lstat('a-file')
633
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
634
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
635
                             sha1sum)
5807.4.3 by John Arbash Meinel
Get the test suite to run clean for bt.test_dirstate bt.test__dirstate bt.test_workingtree
636
            self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
637
                             state._dirblock_state)
638
639
            # Now, before we try to save, grab another dirstate, and take out a
640
            # read lock.
641
            # TODO: jam 20070315 Ideally this would be locked by another
642
            #       process. To make sure the file is really OS locked.
643
            state2 = dirstate.DirState.on_file('dirstate')
644
            state2.lock_read()
645
            try:
646
                # This won't actually write anything, because it couldn't grab
647
                # a write lock. But it shouldn't raise an error, either.
648
                # TODO: jam 20070315 We should probably distinguish between
649
                #       being dirty because of 'update_entry'. And dirty
650
                #       because of real modification. So that save() *does*
651
                #       raise a real error if it fails when we have real
652
                #       modifications.
653
                state.save()
654
            finally:
655
                state2.unlock()
656
        finally:
657
            state.unlock()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
658
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
659
        # The file on disk should not be modified.
660
        state = dirstate.DirState.on_file('dirstate')
661
        state.lock_read()
662
        try:
663
            entry = state._get_entry(0, path_utf8='a-file')
664
            self.assertEqual('', entry[1][0][1])
665
        finally:
666
            state.unlock()
667
3221.1.7 by Martin Pool
Update and rename test for Dirstate._changes_aborted
668
    def test_save_refuses_if_changes_aborted(self):
3207.2.2 by John Arbash Meinel
Fix bug #187169, when an invalid delta is supplied to update_basis_by_delta
669
        self.build_tree(['a-file', 'a-dir/'])
670
        state = dirstate.DirState.initialize('dirstate')
671
        try:
672
            # No stat and no sha1 sum.
673
            state.add('a-file', 'a-file-id', 'file', None, '')
674
            state.save()
675
        finally:
676
            state.unlock()
677
678
        # The dirstate should include TREE_ROOT and 'a-file' and nothing else
679
        expected_blocks = [
680
            ('', [(('', '', 'TREE_ROOT'),
681
                   [('d', '', 0, False, dirstate.DirState.NULLSTAT)])]),
682
            ('', [(('', 'a-file', 'a-file-id'),
683
                   [('f', '', 0, False, dirstate.DirState.NULLSTAT)])]),
684
        ]
685
686
        state = dirstate.DirState.on_file('dirstate')
687
        state.lock_write()
688
        try:
689
            state._read_dirblocks_if_needed()
690
            self.assertEqual(expected_blocks, state._dirblocks)
691
692
            # Now modify the state, but mark it as inconsistent
693
            state.add('a-dir', 'a-dir-id', 'directory', None, '')
3221.1.7 by Martin Pool
Update and rename test for Dirstate._changes_aborted
694
            state._changes_aborted = True
3207.2.2 by John Arbash Meinel
Fix bug #187169, when an invalid delta is supplied to update_basis_by_delta
695
            state.save()
696
        finally:
697
            state.unlock()
698
699
        state = dirstate.DirState.on_file('dirstate')
700
        state.lock_read()
701
        try:
702
            state._read_dirblocks_if_needed()
703
            self.assertEqual(expected_blocks, state._dirblocks)
704
        finally:
705
            state.unlock()
706
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
707
708
class TestDirStateInitialize(TestCaseWithDirState):
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
709
710
    def test_initialize(self):
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
711
        expected_result = ([], [
712
            (('', '', 'TREE_ROOT'), # common details
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
713
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
714
             ])
715
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
716
        state = dirstate.DirState.initialize('dirstate')
717
        try:
718
            self.assertIsInstance(state, dirstate.DirState)
719
            lines = state.get_lines()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
720
        finally:
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
721
            state.unlock()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
722
        # On win32 you can't read from a locked file, even within the same
723
        # process. So we have to unlock and release before we check the file
724
        # contents.
725
        self.assertFileEqual(''.join(lines), 'dirstate')
726
        state.lock_read() # check_state_with_reopen will unlock
727
        self.check_state_with_reopen(expected_result, state)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
728
729
730
class TestDirStateManipulations(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
731
5630.2.6 by John Arbash Meinel
Implement a reset-to-known-state ability for DirState.
732
    def make_minimal_tree(self):
733
        tree1 = self.make_branch_and_memory_tree('tree1')
734
        tree1.lock_write()
735
        self.addCleanup(tree1.unlock)
736
        tree1.add('')
737
        revid1 = tree1.commit('foo')
738
        return tree1, revid1
739
5050.26.1 by John Arbash Meinel
Fix a bug in update_minimal.
740
    def test_update_minimal_updates_id_index(self):
741
        state = self.create_dirstate_with_root_and_subdir()
742
        self.addCleanup(state.unlock)
743
        id_index = state._get_id_index()
744
        self.assertEqual(['a-root-value', 'subdir-id'], sorted(id_index))
745
        state.add('file-name', 'file-id', 'file', None, '')
746
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
747
                         sorted(id_index))
748
        state.update_minimal(('', 'new-name', 'file-id'), 'f',
749
                             path_utf8='new-name')
750
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
751
                         sorted(id_index))
752
        self.assertEqual([('', 'new-name', 'file-id')],
753
                         sorted(id_index['file-id']))
754
        state._validate()
755
2255.2.16 by Robert Collins
Implement WorkingTreeFormat4._write_inventory for better compatability with existing code, letting more test_test_trees pass, now up to test_tree_with_subdirs_and_all_content_types.
756
    def test_set_state_from_inventory_no_content_no_parents(self):
757
        # setting the current inventory is a slow but important api to support.
5630.2.6 by John Arbash Meinel
Implement a reset-to-known-state ability for DirState.
758
        tree1, revid1 = self.make_minimal_tree()
759
        inv = tree1.inventory
760
        root_id = inv.path2id('')
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
761
        expected_result = [], [
762
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
763
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
764
        state = dirstate.DirState.initialize('dirstate')
765
        try:
766
            state.set_state_from_inventory(inv)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
767
            self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
768
                             state._header_state)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
769
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
770
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
771
        except:
772
            state.unlock()
773
            raise
774
        else:
775
            # This will unlock it
776
            self.check_state_with_reopen(expected_result, state)
2255.2.16 by Robert Collins
Implement WorkingTreeFormat4._write_inventory for better compatability with existing code, letting more test_test_trees pass, now up to test_tree_with_subdirs_and_all_content_types.
777
5630.2.6 by John Arbash Meinel
Implement a reset-to-known-state ability for DirState.
778
    def test_set_state_from_scratch_no_parents(self):
779
        tree1, revid1 = self.make_minimal_tree()
780
        inv = tree1.inventory
781
        root_id = inv.path2id('')
782
        expected_result = [], [
783
            (('', '', root_id), [
784
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
785
        state = dirstate.DirState.initialize('dirstate')
786
        try:
787
            state.set_state_from_scratch(inv, [], [])
788
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
789
                             state._header_state)
790
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
791
                             state._dirblock_state)
792
        except:
793
            state.unlock()
794
            raise
795
        else:
796
            # This will unlock it
797
            self.check_state_with_reopen(expected_result, state)
798
799
    def test_set_state_from_scratch_identical_parent(self):
800
        tree1, revid1 = self.make_minimal_tree()
801
        inv = tree1.inventory
802
        root_id = inv.path2id('')
803
        rev_tree1 = tree1.branch.repository.revision_tree(revid1)
804
        d_entry = ('d', '', 0, False, dirstate.DirState.NULLSTAT)
805
        parent_entry = ('d', '', 0, False, revid1)
806
        expected_result = [revid1], [
807
            (('', '', root_id), [d_entry, parent_entry])]
808
        state = dirstate.DirState.initialize('dirstate')
809
        try:
810
            state.set_state_from_scratch(inv, [(revid1, rev_tree1)], [])
811
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
812
                             state._header_state)
813
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
814
                             state._dirblock_state)
815
        except:
816
            state.unlock()
817
            raise
818
        else:
819
            # This will unlock it
820
            self.check_state_with_reopen(expected_result, state)
821
2872.4.3 by Martin Pool
Fix comparison for merge sort in Dirstate.set_state_from_inventory
822
    def test_set_state_from_inventory_preserves_hashcache(self):
2872.4.11 by Martin Pool
Review documentation cleanups
823
        # https://bugs.launchpad.net/bzr/+bug/146176
2872.4.1 by Martin Pool
Add xfail test for #146176
824
        # set_state_from_inventory should preserve the stat and hash value for
825
        # workingtree files that are not changed by the inventory.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
826
2872.4.1 by Martin Pool
Add xfail test for #146176
827
        tree = self.make_branch_and_tree('.')
828
        # depends on the default format using dirstate...
829
        tree.lock_write()
830
        try:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
831
            # make a dirstate with some valid hashcache data
2872.4.1 by Martin Pool
Add xfail test for #146176
832
            # file on disk, but that's not needed for this test
833
            foo_contents = 'contents of foo'
834
            self.build_tree_contents([('foo', foo_contents)])
835
            tree.add('foo', 'foo-id')
836
837
            foo_stat = os.stat('foo')
838
            foo_packed = dirstate.pack_stat(foo_stat)
839
            foo_sha = osutils.sha_string(foo_contents)
840
            foo_size = len(foo_contents)
841
842
            # should not be cached yet, because the file's too fresh
2872.4.8 by Martin Pool
Clear up test code
843
            self.assertEqual(
844
                (('', 'foo', 'foo-id',),
845
                 [('f', '', 0, False, dirstate.DirState.NULLSTAT)]),
846
                tree._dirstate._get_entry(0, 'foo-id'))
2872.4.1 by Martin Pool
Add xfail test for #146176
847
            # poke in some hashcache information - it wouldn't normally be
848
            # stored because it's too fresh
849
            tree._dirstate.update_minimal(
850
                ('', 'foo', 'foo-id'),
851
                'f', False, foo_sha, foo_packed, foo_size, 'foo')
852
            # now should be cached
2872.4.8 by Martin Pool
Clear up test code
853
            self.assertEqual(
854
                (('', 'foo', 'foo-id',),
855
                 [('f', foo_sha, foo_size, False, foo_packed)]),
856
                tree._dirstate._get_entry(0, 'foo-id'))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
857
2872.4.1 by Martin Pool
Add xfail test for #146176
858
            # extract the inventory, and add something to it
859
            inv = tree._get_inventory()
2872.4.3 by Martin Pool
Fix comparison for merge sort in Dirstate.set_state_from_inventory
860
            # should see the file we poked in...
861
            self.assertTrue(inv.has_id('foo-id'))
862
            self.assertTrue(inv.has_filename('foo'))
2872.4.1 by Martin Pool
Add xfail test for #146176
863
            inv.add_path('bar', 'file', 'bar-id')
2872.4.13 by Martin Pool
Validate dirstate during tests
864
            tree._dirstate._validate()
2872.4.11 by Martin Pool
Review documentation cleanups
865
            # this used to cause it to lose its hashcache
2872.4.1 by Martin Pool
Add xfail test for #146176
866
            tree._dirstate.set_state_from_inventory(inv)
2872.4.13 by Martin Pool
Validate dirstate during tests
867
            tree._dirstate._validate()
2872.4.1 by Martin Pool
Add xfail test for #146176
868
        finally:
869
            tree.unlock()
870
871
        tree.lock_read()
872
        try:
873
            # now check that the state still has the original hashcache value
874
            state = tree._dirstate
2872.4.13 by Martin Pool
Validate dirstate during tests
875
            state._validate()
2872.4.1 by Martin Pool
Add xfail test for #146176
876
            foo_tuple = state._get_entry(0, path_utf8='foo')
2872.4.3 by Martin Pool
Fix comparison for merge sort in Dirstate.set_state_from_inventory
877
            self.assertEqual(
2872.4.1 by Martin Pool
Add xfail test for #146176
878
                (('', 'foo', 'foo-id',),
879
                 [('f', foo_sha, len(foo_contents), False,
880
                   dirstate.pack_stat(foo_stat))]),
881
                foo_tuple)
882
        finally:
883
            tree.unlock()
884
2487.1.1 by John Arbash Meinel
Adding a (broken) test that set_state_from_inventory works
885
    def test_set_state_from_inventory_mixed_paths(self):
886
        tree1 = self.make_branch_and_tree('tree1')
887
        self.build_tree(['tree1/a/', 'tree1/a/b/', 'tree1/a-b/',
888
                         'tree1/a/b/foo', 'tree1/a-b/bar'])
889
        tree1.lock_write()
890
        try:
891
            tree1.add(['a', 'a/b', 'a-b', 'a/b/foo', 'a-b/bar'],
892
                      ['a-id', 'b-id', 'a-b-id', 'foo-id', 'bar-id'])
893
            tree1.commit('rev1', rev_id='rev1')
894
            root_id = tree1.get_root_id()
895
            inv = tree1.inventory
896
        finally:
897
            tree1.unlock()
898
        expected_result1 = [('', '', root_id, 'd'),
899
                            ('', 'a', 'a-id', 'd'),
900
                            ('', 'a-b', 'a-b-id', 'd'),
901
                            ('a', 'b', 'b-id', 'd'),
902
                            ('a/b', 'foo', 'foo-id', 'f'),
903
                            ('a-b', 'bar', 'bar-id', 'f'),
904
                           ]
905
        expected_result2 = [('', '', root_id, 'd'),
906
                            ('', 'a', 'a-id', 'd'),
907
                            ('', 'a-b', 'a-b-id', 'd'),
908
                            ('a-b', 'bar', 'bar-id', 'f'),
909
                           ]
910
        state = dirstate.DirState.initialize('dirstate')
911
        try:
912
            state.set_state_from_inventory(inv)
913
            values = []
914
            for entry in state._iter_entries():
915
                values.append(entry[0] + entry[1][0][:1])
916
            self.assertEqual(expected_result1, values)
917
            del inv['b-id']
918
            state.set_state_from_inventory(inv)
919
            values = []
920
            for entry in state._iter_entries():
921
                values.append(entry[0] + entry[1][0][:1])
922
            self.assertEqual(expected_result2, values)
923
        finally:
924
            state.unlock()
925
2255.2.4 by Robert Collins
Snapshot dirstate development
926
    def test_set_path_id_no_parents(self):
927
        """The id of a path can be changed trivally with no parents."""
928
        state = dirstate.DirState.initialize('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
929
        try:
930
            # check precondition to be sure the state does change appropriately.
4634.123.4 by John Arbash Meinel
Start working on some direct dirstate tests.
931
            root_entry = (('', '', 'TREE_ROOT'), [('d', '', 0, False, 'x'*32)])
932
            self.assertEqual([root_entry], list(state._iter_entries()))
933
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
934
            self.assertEqual(root_entry,
935
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
936
            self.assertEqual((None, None),
4634.123.9 by John Arbash Meinel
Fix a bug in the dirstate logic for 'set_path_id'.
937
                             state._get_entry(0, fileid_utf8='second-root-id'))
938
            state.set_path_id('', 'second-root-id')
939
            new_root_entry = (('', '', 'second-root-id'),
4634.123.4 by John Arbash Meinel
Start working on some direct dirstate tests.
940
                              [('d', '', 0, False, 'x'*32)])
941
            expected_rows = [new_root_entry]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
942
            self.assertEqual(expected_rows, list(state._iter_entries()))
4634.123.4 by John Arbash Meinel
Start working on some direct dirstate tests.
943
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
944
            self.assertEqual(new_root_entry, 
4634.123.9 by John Arbash Meinel
Fix a bug in the dirstate logic for 'set_path_id'.
945
                             state._get_entry(0, fileid_utf8='second-root-id'))
4634.123.4 by John Arbash Meinel
Start working on some direct dirstate tests.
946
            self.assertEqual((None, None),
947
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
948
            # should work across save too
949
            state.save()
950
        finally:
951
            state.unlock()
2255.2.15 by Robert Collins
Dirstate - truncate state file fixing bug in saving a smaller file, get more tree_implementation tests passing.
952
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
953
        state.lock_read()
954
        try:
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
955
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
956
            self.assertEqual(expected_rows, list(state._iter_entries()))
957
        finally:
958
            state.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
959
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
960
    def test_set_path_id_with_parents(self):
961
        """Set the root file id in a dirstate with parents"""
962
        mt = self.make_branch_and_tree('mt')
2255.2.178 by Martin Pool
test_set_path_id_with_parents shouldn't depend on tree default root id
963
        # in case the default tree format uses a different root id
964
        mt.set_root_id('TREE_ROOT')
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
965
        mt.commit('foo', rev_id='parent-revid')
966
        rt = mt.branch.repository.revision_tree('parent-revid')
967
        state = dirstate.DirState.initialize('dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
968
        state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
969
        try:
970
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
4634.123.9 by John Arbash Meinel
Fix a bug in the dirstate logic for 'set_path_id'.
971
            root_entry = (('', '', 'TREE_ROOT'),
972
                          [('d', '', 0, False, 'x'*32),
973
                           ('d', '', 0, False, 'parent-revid')])
974
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
975
            self.assertEqual(root_entry,
976
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
977
            self.assertEqual((None, None),
978
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
979
            state.set_path_id('', 'Asecond-root-id')
2255.2.177 by Martin Pool
merge dirstate sorting fix, add more validation tests
980
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
981
            # now see that it is what we expected
4634.123.9 by John Arbash Meinel
Fix a bug in the dirstate logic for 'set_path_id'.
982
            old_root_entry = (('', '', 'TREE_ROOT'),
983
                              [('a', '', 0, False, ''),
984
                               ('d', '', 0, False, 'parent-revid')])
985
            new_root_entry = (('', '', 'Asecond-root-id'),
986
                              [('d', '', 0, False, ''),
987
                               ('a', '', 0, False, '')])
988
            expected_rows = [new_root_entry, old_root_entry]
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
989
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
990
            self.assertEqual(expected_rows, list(state._iter_entries()))
4634.123.9 by John Arbash Meinel
Fix a bug in the dirstate logic for 'set_path_id'.
991
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
992
            self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
993
            self.assertEqual((None, None),
994
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
995
            self.assertEqual(old_root_entry,
996
                             state._get_entry(1, fileid_utf8='TREE_ROOT'))
997
            self.assertEqual(new_root_entry,
998
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
999
            self.assertEqual((None, None),
1000
                             state._get_entry(1, fileid_utf8='Asecond-root-id'))
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
1001
            # should work across save too
1002
            state.save()
1003
        finally:
1004
            state.unlock()
1005
        # now flush & check we get the same
1006
        state = dirstate.DirState.on_file('dirstate')
1007
        state.lock_read()
1008
        try:
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
1009
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
1010
            self.assertEqual(expected_rows, list(state._iter_entries()))
1011
        finally:
1012
            state.unlock()
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
1013
        # now change within an existing file-backed state
1014
        state.lock_write()
1015
        try:
1016
            state._validate()
1017
            state.set_path_id('', 'tree-root-2')
1018
            state._validate()
1019
        finally:
1020
            state.unlock()
1021
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1022
    def test_set_parent_trees_no_content(self):
1023
        # set_parent_trees is a slow but important api to support.
1024
        tree1 = self.make_branch_and_memory_tree('tree1')
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
1025
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1026
        try:
1027
            tree1.add('')
1028
            revid1 = tree1.commit('foo')
1029
        finally:
1030
            tree1.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
1031
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1032
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
1033
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1034
        try:
1035
            revid2 = tree2.commit('foo')
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
1036
            root_id = tree2.get_root_id()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1037
        finally:
1038
            tree2.unlock()
1039
        state = dirstate.DirState.initialize('dirstate')
1040
        try:
1041
            state.set_path_id('', root_id)
1042
            state.set_parent_trees(
1043
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1044
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
1045
                 ('ghost-rev', None)),
1046
                ['ghost-rev'])
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1047
            # check we can reopen and use the dirstate after setting parent
1048
            # trees.
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
1049
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1050
            state.save()
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
1051
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1052
        finally:
1053
            state.unlock()
2255.2.3 by Robert Collins
Split out working tree format 4 to its own file, create stub dirstate revision object, start working on dirstate.set_parent_trees - a key failure point.
1054
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1055
        state.lock_write()
1056
        try:
1057
            self.assertEqual([revid1, revid2, 'ghost-rev'],
1058
                             state.get_parent_ids())
1059
            # iterating the entire state ensures that the state is parsable.
1060
            list(state._iter_entries())
1061
            # be sure that it sets not appends - change it
1062
            state.set_parent_trees(
1063
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1064
                 ('ghost-rev', None)),
1065
                ['ghost-rev'])
1066
            # and now put it back.
1067
            state.set_parent_trees(
1068
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1069
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
1070
                 ('ghost-rev', tree2.branch.repository.revision_tree(
1071
                                   _mod_revision.NULL_REVISION))),
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1072
                ['ghost-rev'])
1073
            self.assertEqual([revid1, revid2, 'ghost-rev'],
1074
                             state.get_parent_ids())
1075
            # the ghost should be recorded as such by set_parent_trees.
1076
            self.assertEqual(['ghost-rev'], state.get_ghosts())
1077
            self.assertEqual(
1078
                [(('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
1079
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1080
                  ('d', '', 0, False, revid1),
4599.4.24 by Robert Collins
Prepare dirstate tests for 2a as default.
1081
                  ('d', '', 0, False, revid1)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1082
                  ])],
1083
                list(state._iter_entries()))
1084
        finally:
1085
            state.unlock()
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
1086
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1087
    def test_set_parent_trees_file_missing_from_tree(self):
1088
        # Adding a parent tree may reference files not in the current state.
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1089
        # they should get listed just once by id, even if they are in two
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1090
        # separate trees.
1091
        # set_parent_trees is a slow but important api to support.
1092
        tree1 = self.make_branch_and_memory_tree('tree1')
1093
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1094
        try:
1095
            tree1.add('')
1096
            tree1.add(['a file'], ['file-id'], ['file'])
1097
            tree1.put_file_bytes_non_atomic('file-id', 'file-content')
1098
            revid1 = tree1.commit('foo')
1099
        finally:
1100
            tree1.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1101
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1102
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1103
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1104
        try:
1105
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
1106
            revid2 = tree2.commit('foo')
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
1107
            root_id = tree2.get_root_id()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1108
        finally:
1109
            tree2.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1110
        # check the layout in memory
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1111
        expected_result = [revid1.encode('utf8'), revid2.encode('utf8')], [
1112
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
1113
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1114
             ('d', '', 0, False, revid1.encode('utf8')),
4599.4.24 by Robert Collins
Prepare dirstate tests for 2a as default.
1115
             ('d', '', 0, False, revid1.encode('utf8'))
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1116
             ]),
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1117
            (('', 'a file', 'file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1118
             ('a', '', 0, False, ''),
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1119
             ('f', '2439573625385400f2a669657a7db6ae7515d371', 12, False,
1120
              revid1.encode('utf8')),
1121
             ('f', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False,
1122
              revid2.encode('utf8'))
1123
             ])
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1124
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1125
        state = dirstate.DirState.initialize('dirstate')
1126
        try:
1127
            state.set_path_id('', root_id)
1128
            state.set_parent_trees(
1129
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1130
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
1131
                 ), [])
1132
        except:
1133
            state.unlock()
1134
            raise
1135
        else:
1136
            # check_state_with_reopen will unlock
1137
            self.check_state_with_reopen(expected_result, state)
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
1138
1852.13.20 by Robert Collins
Steps toward an object model.
1139
    ### add a path via _set_data - so we dont need delta work, just
1140
    # raw data in, and ensure that it comes out via get_lines happily.
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
1141
1852.13.25 by Robert Collins
Snapshot state
1142
    def test_add_path_to_root_no_parents_all_data(self):
1143
        # The most trivial addition of a path is when there are no parents and
1144
        # its in the root and all data about the file is supplied
1145
        self.build_tree(['a file'])
1146
        stat = os.lstat('a file')
1147
        # the 1*20 is the sha1 pretend value.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1148
        state = dirstate.DirState.initialize('dirstate')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1149
        expected_entries = [
1150
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1151
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1152
             ]),
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
1153
            (('', 'a file', 'a-file-id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1154
             ('f', '1'*20, 19, False, dirstate.pack_stat(stat)), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1155
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1156
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1157
        try:
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
1158
            state.add('a file', 'a-file-id', 'file', stat, '1'*20)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1159
            # having added it, it should be in the output of iter_entries.
1160
            self.assertEqual(expected_entries, list(state._iter_entries()))
1161
            # saving and reloading should not affect this.
1162
            state.save()
1163
        finally:
1164
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1165
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1166
        state.lock_read()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1167
        self.addCleanup(state.unlock)
1168
        self.assertEqual(expected_entries, list(state._iter_entries()))
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1169
1170
    def test_add_path_to_unversioned_directory(self):
2255.2.29 by Robert Collins
Change the error raised from Dirstate.add for an unversioned parent path to match the WorkingTree interface.
1171
        """Adding a path to an unversioned directory should error.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1172
1173
        This is a duplicate of TestWorkingTree.test_add_in_unversioned,
2255.2.29 by Robert Collins
Change the error raised from Dirstate.add for an unversioned parent path to match the WorkingTree interface.
1174
        once dirstate is stable and if it is merged with WorkingTree3, consider
1175
        removing this copy of the test.
1176
        """
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1177
        self.build_tree(['unversioned/', 'unversioned/a file'])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1178
        state = dirstate.DirState.initialize('dirstate')
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1179
        self.addCleanup(state.unlock)
1180
        self.assertRaises(errors.NotVersionedError, state.add,
1181
                          'unversioned/a file', 'a-file-id', 'file', None, None)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1182
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1183
    def test_add_directory_to_root_no_parents_all_data(self):
1184
        # The most trivial addition of a dir is when there are no parents and
1185
        # its in the root and all data about the file is supplied
1186
        self.build_tree(['a dir/'])
1187
        stat = os.lstat('a dir')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1188
        expected_entries = [
1189
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1190
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1191
             ]),
1192
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1193
             ('d', '', 0, False, dirstate.pack_stat(stat)), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1194
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1195
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1196
        state = dirstate.DirState.initialize('dirstate')
1197
        try:
1198
            state.add('a dir', 'a dir id', 'directory', stat, None)
1199
            # having added it, it should be in the output of iter_entries.
1200
            self.assertEqual(expected_entries, list(state._iter_entries()))
1201
            # saving and reloading should not affect this.
1202
            state.save()
1203
        finally:
1204
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
1205
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1206
        state.lock_read()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1207
        self.addCleanup(state.unlock)
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
1208
        state._validate()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1209
        self.assertEqual(expected_entries, list(state._iter_entries()))
1852.13.25 by Robert Collins
Snapshot state
1210
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1211
    def _test_add_symlink_to_root_no_parents_all_data(self, link_name, target):
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1212
        # The most trivial addition of a symlink when there are no parents and
1213
        # its in the root and all data about the file is supplied
2321.3.8 by Alexander Belchenko
Cleanup patch after John's review
1214
        # bzr doesn't support fake symlinks on windows, yet.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1215
        self.requireFeature(features.SymlinkFeature)
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1216
        os.symlink(target, link_name)
1217
        stat = os.lstat(link_name)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1218
        expected_entries = [
1219
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1220
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1221
             ]),
4241.14.11 by Vincent Ladeuil
Fix wrong encoding.
1222
            (('', link_name.encode('UTF-8'), 'a link id'), [
1223
             ('l', target.encode('UTF-8'), stat[6],
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1224
              False, dirstate.pack_stat(stat)), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1225
             ]),
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1226
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1227
        state = dirstate.DirState.initialize('dirstate')
1228
        try:
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1229
            state.add(link_name, 'a link id', 'symlink', stat,
4241.14.11 by Vincent Ladeuil
Fix wrong encoding.
1230
                      target.encode('UTF-8'))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1231
            # having added it, it should be in the output of iter_entries.
1232
            self.assertEqual(expected_entries, list(state._iter_entries()))
1233
            # saving and reloading should not affect this.
1234
            state.save()
1235
        finally:
1236
            state.unlock()
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1237
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1238
        state.lock_read()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1239
        self.addCleanup(state.unlock)
1240
        self.assertEqual(expected_entries, list(state._iter_entries()))
1241
1242
    def test_add_symlink_to_root_no_parents_all_data(self):
1243
        self._test_add_symlink_to_root_no_parents_all_data('a link', 'target')
1244
1245
    def test_add_symlink_unicode_to_root_no_parents_all_data(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
1246
        self.requireFeature(features.UnicodeFilenameFeature)
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1247
        self._test_add_symlink_to_root_no_parents_all_data(
1248
            u'\N{Euro Sign}link', u'targ\N{Euro Sign}et')
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1249
1250
    def test_add_directory_and_child_no_parents_all_data(self):
1251
        # after adding a directory, we should be able to add children to it.
1252
        self.build_tree(['a dir/', 'a dir/a file'])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1253
        dirstat = os.lstat('a dir')
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1254
        filestat = os.lstat('a dir/a file')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1255
        expected_entries = [
1256
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1257
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1258
             ]),
1259
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1260
             ('d', '', 0, False, dirstate.pack_stat(dirstat)), # current tree
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1261
             ]),
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
1262
            (('a dir', 'a file', 'a-file-id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1263
             ('f', '1'*20, 25, False,
1264
              dirstate.pack_stat(filestat)), # current tree details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1265
             ]),
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1266
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1267
        state = dirstate.DirState.initialize('dirstate')
1268
        try:
1269
            state.add('a dir', 'a dir id', 'directory', dirstat, None)
3010.1.2 by Robert Collins
Use valid file-ids for dirstate tests.
1270
            state.add('a dir/a file', 'a-file-id', 'file', filestat, '1'*20)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1271
            # added it, it should be in the output of iter_entries.
1272
            self.assertEqual(expected_entries, list(state._iter_entries()))
1273
            # saving and reloading should not affect this.
1274
            state.save()
1275
        finally:
1276
            state.unlock()
2255.2.14 by Robert Collins
Dirstate: fix adding of directories to setup the next directories block, and test representation of symlinks. Also fix iter_rows to not reset the dirty bit.
1277
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1278
        state.lock_read()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1279
        self.addCleanup(state.unlock)
1280
        self.assertEqual(expected_entries, list(state._iter_entries()))
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1281
2255.7.93 by Martin Pool
Add support for tree-references in dirstate
1282
    def test_add_tree_reference(self):
1283
        # make a dirstate and add a tree reference
1284
        state = dirstate.DirState.initialize('dirstate')
1285
        expected_entry = (
1286
            ('', 'subdir', 'subdir-id'),
1287
            [('t', 'subtree-123123', 0, False,
1288
              'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')],
1289
            )
1290
        try:
1291
            state.add('subdir', 'subdir-id', 'tree-reference', None, 'subtree-123123')
1292
            entry = state._get_entry(0, 'subdir-id', 'subdir')
1293
            self.assertEqual(entry, expected_entry)
1294
            state._validate()
1295
            state.save()
1296
        finally:
1297
            state.unlock()
1298
        # now check we can read it back
1299
        state.lock_read()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1300
        self.addCleanup(state.unlock)
2255.7.93 by Martin Pool
Add support for tree-references in dirstate
1301
        state._validate()
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1302
        entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1303
        self.assertEqual(entry, entry2)
1304
        self.assertEqual(entry, expected_entry)
1305
        # and lookup by id should work too
1306
        entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1307
        self.assertEqual(entry, expected_entry)
2255.7.93 by Martin Pool
Add support for tree-references in dirstate
1308
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1309
    def test_add_forbidden_names(self):
1310
        state = dirstate.DirState.initialize('dirstate')
2255.2.233 by John Arbash Meinel
DirState.initialize returns a locked state, unlock as part of cleanup.
1311
        self.addCleanup(state.unlock)
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1312
        self.assertRaises(errors.BzrError,
1313
            state.add, '.', 'ass-id', 'directory', None, None)
1314
        self.assertRaises(errors.BzrError,
1315
            state.add, '..', 'ass-id', 'directory', None, None)
1316
4536.4.1 by Robert Collins
Fix dirstate.set_state_from_inventory to have a more stable old_iterator, fixing rename problems in new trees. (Robert Collins, bug 395556)
1317
    def test_set_state_with_rename_b_a_bug_395556(self):
1318
        # bug 395556 uncovered a bug where the dirstate ends up with a false
1319
        # relocation record - in a tree with no parents there should be no
1320
        # absent or relocated records. This then leads to further corruption
1321
        # when a commit occurs, as the incorrect relocation gathers an
1322
        # incorrect absent in tree 1, and future changes go to pot.
1323
        tree1 = self.make_branch_and_tree('tree1')
1324
        self.build_tree(['tree1/b'])
1325
        tree1.lock_write()
1326
        try:
1327
            tree1.add(['b'], ['b-id'])
1328
            root_id = tree1.get_root_id()
1329
            inv = tree1.inventory
1330
            state = dirstate.DirState.initialize('dirstate')
1331
            try:
1332
                # Set the initial state with 'b'
1333
                state.set_state_from_inventory(inv)
1334
                inv.rename('b-id', root_id, 'a')
1335
                # Set the new state with 'a', which currently corrupts.
1336
                state.set_state_from_inventory(inv)
1337
                expected_result1 = [('', '', root_id, 'd'),
1338
                                    ('', 'a', 'b-id', 'f'),
1339
                                   ]
1340
                values = []
1341
                for entry in state._iter_entries():
1342
                    values.append(entry[0] + entry[1][0][:1])
1343
                self.assertEqual(expected_result1, values)
1344
            finally:
1345
                state.unlock()
1346
        finally:
1347
            tree1.unlock()
1348
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1349
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1350
class TestDirStateHashUpdates(TestCaseWithDirState):
1351
1352
    def do_update_entry(self, state, path):
1353
        entry = state._get_entry(0, path_utf8=path)
1354
        stat = os.lstat(path)
1355
        return dirstate.update_entry(state, entry, os.path.abspath(path), stat)
1356
5912.1.1 by John Arbash Meinel
Fix a test that was failing on win32.
1357
    def _read_state_content(self, state):
1358
        """Read the content of the dirstate file.
1359
1360
        On Windows when one process locks a file, you can't even open() the
1361
        file in another process (to read it). So we go directly to
1362
        state._state_file. This should always be the exact disk representation,
1363
        so it is reasonable to do so.
1364
        DirState also always seeks before reading, so it doesn't matter if we
1365
        bump the file pointer.
1366
        """
1367
        state._state_file.seek(0)
1368
        return state._state_file.read()
1369
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1370
    def test_worth_saving_limit_avoids_writing(self):
5807.4.6 by John Arbash Meinel
Merge newer bzr.dev and resolve conflicts.
1371
        tree = self.make_branch_and_tree('.')
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1372
        self.build_tree(['c', 'd'])
5807.4.6 by John Arbash Meinel
Merge newer bzr.dev and resolve conflicts.
1373
        tree.lock_write()
1374
        tree.add(['c', 'd'], ['c-id', 'd-id'])
1375
        tree.commit('add c and d')
1376
        state = InstrumentedDirState.on_file(tree.current_dirstate()._filename,
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1377
                                             worth_saving_limit=2)
5807.4.6 by John Arbash Meinel
Merge newer bzr.dev and resolve conflicts.
1378
        tree.unlock()
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1379
        state.lock_write()
1380
        self.addCleanup(state.unlock)
1381
        state._read_dirblocks_if_needed()
1382
        state.adjust_time(+20) # Allow things to be cached
1383
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1384
                         state._dirblock_state)
5912.1.1 by John Arbash Meinel
Fix a test that was failing on win32.
1385
        content = self._read_state_content(state)
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1386
        self.do_update_entry(state, 'c')
1387
        self.assertEqual(1, len(state._known_hash_changes))
1388
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
1389
                         state._dirblock_state)
1390
        state.save()
1391
        # It should not have set the state to IN_MEMORY_UNMODIFIED because the
1392
        # hash values haven't been written out.
1393
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
1394
                         state._dirblock_state)
5912.1.1 by John Arbash Meinel
Fix a test that was failing on win32.
1395
        self.assertEqual(content, self._read_state_content(state))
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1396
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
1397
                         state._dirblock_state)
1398
        self.do_update_entry(state, 'd')
1399
        self.assertEqual(2, len(state._known_hash_changes))
1400
        state.save()
1401
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1402
                         state._dirblock_state)
1403
        self.assertEqual(0, len(state._known_hash_changes))
1404
5807.4.6 by John Arbash Meinel
Merge newer bzr.dev and resolve conflicts.
1405
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1406
class TestGetLines(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
1407
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1408
    def test_get_line_with_2_rows(self):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1409
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1410
        try:
2255.7.20 by John Arbash Meinel
update test for format 3, and enable caching of path split while lock is held.
1411
            self.assertEqual(['#bazaar dirstate flat format 3\n',
2255.2.239 by Robert Collins
Change from adler to crc checksums, as adler32 in python is not stable from 32 to 64 bit systems.
1412
                'crc32: 41262208\n',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1413
                'num_entries: 2\n',
1414
                '0\x00\n\x00'
1415
                '0\x00\n\x00'
1416
                '\x00\x00a-root-value\x00'
1417
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1418
                '\x00subdir\x00subdir-id\x00'
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1419
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1420
                ], state.get_lines())
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1421
        finally:
1422
            state.unlock()
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1423
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1424
    def test_entry_to_line(self):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1425
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1426
        try:
1427
            self.assertEqual(
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1428
                '\x00\x00a-root-value\x00d\x00\x000\x00n'
1429
                '\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1430
                state._entry_to_line(state._dirblocks[0][1][0]))
1431
        finally:
1432
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1433
1434
    def test_entry_to_line_with_parent(self):
1435
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1436
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1437
            ('d', '', 0, False, packed_stat), # current tree details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1438
             # first: a pointer to the current location
1439
            ('a', 'dirname/basename', 0, False, ''),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1440
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1441
        state = dirstate.DirState.initialize('dirstate')
1442
        try:
1443
            self.assertEqual(
1444
                '\x00\x00a-root-value\x00'
1445
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1446
                'a\x00dirname/basename\x000\x00n\x00',
1447
                state._entry_to_line(root_entry))
1448
        finally:
1449
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1450
1451
    def test_entry_to_line_with_two_parents_at_different_paths(self):
1452
        # / in the tree, at / in one parent and /dirname/basename in the other.
1453
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1454
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1455
            ('d', '', 0, False, packed_stat), # current tree details
1456
            ('d', '', 0, False, 'rev_id'), # first parent details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1457
             # second: a pointer to the current location
1458
            ('a', 'dirname/basename', 0, False, ''),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1459
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1460
        state = dirstate.DirState.initialize('dirstate')
1461
        try:
1462
            self.assertEqual(
1463
                '\x00\x00a-root-value\x00'
1464
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1465
                'd\x00\x000\x00n\x00rev_id\x00'
1466
                'a\x00dirname/basename\x000\x00n\x00',
1467
                state._entry_to_line(root_entry))
1468
        finally:
1469
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1470
1471
    def test_iter_entries(self):
1472
        # we should be able to iterate the dirstate entries from end to end
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1473
        # this is for get_lines to be easy to read.
1474
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1475
        dirblocks = []
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1476
        root_entries = [(('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1477
            ('d', '', 0, False, packed_stat), # current tree details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1478
            ])]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1479
        dirblocks.append(('', root_entries))
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1480
        # add two files in the root
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1481
        subdir_entry = ('', 'subdir', 'subdir-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1482
            ('d', '', 0, False, packed_stat), # current tree details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1483
            ]
1484
        afile_entry = ('', 'afile', 'afile-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1485
            ('f', 'sha1value', 34, False, packed_stat), # current tree details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1486
            ]
1487
        dirblocks.append(('', [subdir_entry, afile_entry]))
1852.13.24 by Robert Collins
Get back to the broken-pending-revision-tree-from-dirstate state of development, changing dirstate from_tree to use _set_data rather than generating lines itself.
1488
        # and one in subdir
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1489
        file_entry2 = ('subdir', '2file', '2file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1490
            ('f', 'sha1value', 23, False, packed_stat), # current tree details
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1491
            ]
1492
        dirblocks.append(('subdir', [file_entry2]))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1493
        state = dirstate.DirState.initialize('dirstate')
1494
        try:
1495
            state._set_data([], dirblocks)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1496
            expected_entries = [root_entries[0], subdir_entry, afile_entry,
1497
                                file_entry2]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1498
            self.assertEqual(expected_entries, list(state._iter_entries()))
1499
        finally:
1500
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1501
1502
1503
class TestGetBlockRowIndex(TestCaseWithDirState):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1504
1505
    def assertBlockRowIndexEqual(self, block_index, row_index, dir_present,
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1506
        file_present, state, dirname, basename, tree_index):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1507
        self.assertEqual((block_index, row_index, dir_present, file_present),
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1508
            state._get_block_entry_index(dirname, basename, tree_index))
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1509
        if dir_present:
1510
            block = state._dirblocks[block_index]
1511
            self.assertEqual(dirname, block[0])
1512
        if dir_present and file_present:
1513
            row = state._dirblocks[block_index][1][row_index]
1514
            self.assertEqual(dirname, row[0][0])
1515
            self.assertEqual(basename, row[0][1])
1516
1517
    def test_simple_structure(self):
1518
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1519
        self.addCleanup(state.unlock)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1520
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
1521
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
1522
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
1523
        self.assertBlockRowIndexEqual(2, 0, False, False, state, 'a', 'foo', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1524
        self.assertBlockRowIndexEqual(2, 0, False, False, state,
1525
                                      'subdir', 'foo', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1526
1527
    def test_complex_structure_exists(self):
1528
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1529
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1530
        # Make sure we can find everything that exists
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1531
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1532
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
1533
        self.assertBlockRowIndexEqual(1, 1, True, True, state, '', 'b', 0)
1534
        self.assertBlockRowIndexEqual(1, 2, True, True, state, '', 'c', 0)
1535
        self.assertBlockRowIndexEqual(1, 3, True, True, state, '', 'd', 0)
1536
        self.assertBlockRowIndexEqual(2, 0, True, True, state, 'a', 'e', 0)
1537
        self.assertBlockRowIndexEqual(2, 1, True, True, state, 'a', 'f', 0)
1538
        self.assertBlockRowIndexEqual(3, 0, True, True, state, 'b', 'g', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1539
        self.assertBlockRowIndexEqual(3, 1, True, True, state,
1540
                                      'b', 'h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1541
1542
    def test_complex_structure_missing(self):
1543
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1544
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1545
        # Make sure things would be inserted in the right locations
1546
        # '_' comes before 'a'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1547
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1548
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', '_', 0)
1549
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'aa', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1550
        self.assertBlockRowIndexEqual(1, 4, True, False, state,
1551
                                      '', 'h\xc3\xa5', 0)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1552
        self.assertBlockRowIndexEqual(2, 0, False, False, state, '_', 'a', 0)
1553
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'aa', 'a', 0)
1554
        self.assertBlockRowIndexEqual(4, 0, False, False, state, 'bb', 'a', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1555
        # This would be inserted between a/ and b/
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1556
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'a/e', 'a', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1557
        # Put at the end
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1558
        self.assertBlockRowIndexEqual(4, 0, False, False, state, 'e', 'a', 0)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1559
1560
1561
class TestGetEntry(TestCaseWithDirState):
1562
1563
    def assertEntryEqual(self, dirname, basename, file_id, state, path, index):
1564
        """Check that the right entry is returned for a request to getEntry."""
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
1565
        entry = state._get_entry(index, path_utf8=path)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1566
        if file_id is None:
1567
            self.assertEqual((None, None), entry)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1568
        else:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1569
            cur = entry[0]
1570
            self.assertEqual((dirname, basename, file_id), cur[:3])
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1571
1572
    def test_simple_structure(self):
1573
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1574
        self.addCleanup(state.unlock)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1575
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1576
        self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
1577
        self.assertEntryEqual(None, None, None, state, 'missing', 0)
1578
        self.assertEntryEqual(None, None, None, state, 'missing/foo', 0)
1579
        self.assertEntryEqual(None, None, None, state, 'subdir/foo', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1580
1581
    def test_complex_structure_exists(self):
1582
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1583
        self.addCleanup(state.unlock)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1584
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1585
        self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
1586
        self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
1587
        self.assertEntryEqual('', 'c', 'c-file', state, 'c', 0)
1588
        self.assertEntryEqual('', 'd', 'd-file', state, 'd', 0)
1589
        self.assertEntryEqual('a', 'e', 'e-dir', state, 'a/e', 0)
1590
        self.assertEntryEqual('a', 'f', 'f-file', state, 'a/f', 0)
1591
        self.assertEntryEqual('b', 'g', 'g-file', state, 'b/g', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1592
        self.assertEntryEqual('b', 'h\xc3\xa5', 'h-\xc3\xa5-file', state,
1593
                              'b/h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1594
1595
    def test_complex_structure_missing(self):
1596
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1597
        self.addCleanup(state.unlock)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1598
        self.assertEntryEqual(None, None, None, state, '_', 0)
1599
        self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
1600
        self.assertEntryEqual(None, None, None, state, 'a/b', 0)
1601
        self.assertEntryEqual(None, None, None, state, 'c/d', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1602
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1603
    def test_get_entry_uninitialized(self):
1604
        """Calling get_entry will load data if it needs to"""
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1605
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1606
        try:
1607
            state.save()
1608
        finally:
1609
            state.unlock()
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1610
        del state
1611
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1612
        state.lock_read()
1613
        try:
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1614
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1615
                             state._header_state)
1616
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1617
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1618
            self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1619
        finally:
1620
            state.unlock()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1621
1622
2929.2.1 by Robert Collins
* Commit updates the state of the working tree via a delta rather than
1623
class TestIterChildEntries(TestCaseWithDirState):
1624
1625
    def create_dirstate_with_two_trees(self):
1626
        """This dirstate contains multiple files and directories.
1627
1628
         /        a-root-value
1629
         a/       a-dir
1630
         b/       b-dir
1631
         c        c-file
1632
         d        d-file
1633
         a/e/     e-dir
1634
         a/f      f-file
1635
         b/g      g-file
1636
         b/h\xc3\xa5  h-\xc3\xa5-file  #This is u'\xe5' encoded into utf-8
1637
1638
        Notice that a/e is an empty directory.
1639
1640
        There is one parent tree, which has the same shape with the following variations:
1641
        b/g in the parent is gone.
1642
        b/h in the parent has a different id
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1643
        b/i is new in the parent
2929.2.1 by Robert Collins
* Commit updates the state of the working tree via a delta rather than
1644
        c is renamed to b/j in the parent
1645
1646
        :return: The dirstate, still write-locked.
1647
        """
1648
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1649
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1650
        NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1651
        root_entry = ('', '', 'a-root-value'), [
1652
            ('d', '', 0, False, packed_stat),
1653
            ('d', '', 0, False, 'parent-revid'),
1654
            ]
1655
        a_entry = ('', 'a', 'a-dir'), [
1656
            ('d', '', 0, False, packed_stat),
1657
            ('d', '', 0, False, 'parent-revid'),
1658
            ]
1659
        b_entry = ('', 'b', 'b-dir'), [
1660
            ('d', '', 0, False, packed_stat),
1661
            ('d', '', 0, False, 'parent-revid'),
1662
            ]
1663
        c_entry = ('', 'c', 'c-file'), [
1664
            ('f', null_sha, 10, False, packed_stat),
1665
            ('r', 'b/j', 0, False, ''),
1666
            ]
1667
        d_entry = ('', 'd', 'd-file'), [
1668
            ('f', null_sha, 20, False, packed_stat),
1669
            ('f', 'd', 20, False, 'parent-revid'),
1670
            ]
1671
        e_entry = ('a', 'e', 'e-dir'), [
1672
            ('d', '', 0, False, packed_stat),
1673
            ('d', '', 0, False, 'parent-revid'),
1674
            ]
1675
        f_entry = ('a', 'f', 'f-file'), [
1676
            ('f', null_sha, 30, False, packed_stat),
1677
            ('f', 'f', 20, False, 'parent-revid'),
1678
            ]
1679
        g_entry = ('b', 'g', 'g-file'), [
1680
            ('f', null_sha, 30, False, packed_stat),
1681
            NULL_PARENT_DETAILS,
1682
            ]
1683
        h_entry1 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file1'), [
1684
            ('f', null_sha, 40, False, packed_stat),
1685
            NULL_PARENT_DETAILS,
1686
            ]
1687
        h_entry2 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file2'), [
1688
            NULL_PARENT_DETAILS,
1689
            ('f', 'h', 20, False, 'parent-revid'),
1690
            ]
1691
        i_entry = ('b', 'i', 'i-file'), [
1692
            NULL_PARENT_DETAILS,
1693
            ('f', 'h', 20, False, 'parent-revid'),
1694
            ]
1695
        j_entry = ('b', 'j', 'c-file'), [
1696
            ('r', 'c', 0, False, ''),
1697
            ('f', 'j', 20, False, 'parent-revid'),
1698
            ]
1699
        dirblocks = []
1700
        dirblocks.append(('', [root_entry]))
1701
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
1702
        dirblocks.append(('a', [e_entry, f_entry]))
1703
        dirblocks.append(('b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1704
        state = dirstate.DirState.initialize('dirstate')
1705
        state._validate()
1706
        try:
1707
            state._set_data(['parent'], dirblocks)
1708
        except:
1709
            state.unlock()
1710
            raise
1711
        return state, dirblocks
1712
1713
    def test_iter_children_b(self):
1714
        state, dirblocks = self.create_dirstate_with_two_trees()
1715
        self.addCleanup(state.unlock)
1716
        expected_result = []
1717
        expected_result.append(dirblocks[3][1][2]) # h2
1718
        expected_result.append(dirblocks[3][1][3]) # i
1719
        expected_result.append(dirblocks[3][1][4]) # j
1720
        self.assertEqual(expected_result,
1721
            list(state._iter_child_entries(1, 'b')))
1722
2929.2.2 by Robert Collins
Review feedback on dirstate update_basis_via_delta logic.
1723
    def test_iter_child_root(self):
1724
        state, dirblocks = self.create_dirstate_with_two_trees()
1725
        self.addCleanup(state.unlock)
1726
        expected_result = []
1727
        expected_result.append(dirblocks[1][1][0]) # a
1728
        expected_result.append(dirblocks[1][1][1]) # b
1729
        expected_result.append(dirblocks[1][1][3]) # d
1730
        expected_result.append(dirblocks[2][1][0]) # e
1731
        expected_result.append(dirblocks[2][1][1]) # f
1732
        expected_result.append(dirblocks[3][1][2]) # h2
1733
        expected_result.append(dirblocks[3][1][3]) # i
1734
        expected_result.append(dirblocks[3][1][4]) # j
1735
        self.assertEqual(expected_result,
1736
            list(state._iter_child_entries(1, '')))
1737
2929.2.1 by Robert Collins
* Commit updates the state of the working tree via a delta rather than
1738
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1739
class TestDirstateSortOrder(tests.TestCaseWithTransport):
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1740
    """Test that DirState adds entries in the right order."""
1741
1742
    def test_add_sorting(self):
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1743
        """Add entries in lexicographical order, we get path sorted order.
1744
1745
        This tests it to a depth of 4, to make sure we don't just get it right
1746
        at a single depth. 'a/a' should come before 'a-a', even though it
1747
        doesn't lexicographically.
1748
        """
1749
        dirs = ['a', 'a/a', 'a/a/a', 'a/a/a/a',
1750
                'a-a', 'a/a-a', 'a/a/a-a', 'a/a/a/a-a',
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1751
               ]
1752
        null_sha = ''
1753
        state = dirstate.DirState.initialize('dirstate')
1754
        self.addCleanup(state.unlock)
1755
1756
        fake_stat = os.stat('dirstate')
1757
        for d in dirs:
1758
            d_id = d.replace('/', '_')+'-id'
1759
            file_path = d + '/f'
1760
            file_id = file_path.replace('/', '_')+'-id'
1761
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1762
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1763
1764
        expected = ['', '', 'a',
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1765
                'a/a', 'a/a/a', 'a/a/a/a',
1766
                'a/a/a/a-a', 'a/a/a-a', 'a/a-a', 'a-a',
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1767
               ]
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1768
        split = lambda p:p.split('/')
1769
        self.assertEqual(sorted(expected, key=split), expected)
1770
        dirblock_names = [d[0] for d in state._dirblocks]
1771
        self.assertEqual(expected, dirblock_names)
1772
1773
    def test_set_parent_trees_correct_order(self):
1774
        """After calling set_parent_trees() we should maintain the order."""
1775
        dirs = ['a', 'a-a', 'a/a']
1776
        null_sha = ''
1777
        state = dirstate.DirState.initialize('dirstate')
1778
        self.addCleanup(state.unlock)
1779
1780
        fake_stat = os.stat('dirstate')
1781
        for d in dirs:
1782
            d_id = d.replace('/', '_')+'-id'
1783
            file_path = d + '/f'
1784
            file_id = file_path.replace('/', '_')+'-id'
1785
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1786
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1787
1788
        expected = ['', '', 'a', 'a/a', 'a-a']
1789
        dirblock_names = [d[0] for d in state._dirblocks]
1790
        self.assertEqual(expected, dirblock_names)
1791
1792
        # *really* cheesy way to just get an empty tree
1793
        repo = self.make_repository('repo')
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
1794
        empty_tree = repo.revision_tree(_mod_revision.NULL_REVISION)
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1795
        state.set_parent_trees([('null:', empty_tree)], [])
1796
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1797
        dirblock_names = [d[0] for d in state._dirblocks]
1798
        self.assertEqual(expected, dirblock_names)
1799
1800
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1801
class InstrumentedDirState(dirstate.DirState):
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1802
    """An DirState with instrumented sha1 functionality."""
1803
5807.4.5 by John Arbash Meinel
Start adding tests that _worth_saving_limit works as expected.
1804
    def __init__(self, path, sha1_provider, worth_saving_limit=0):
1805
        super(InstrumentedDirState, self).__init__(path, sha1_provider,
1806
            worth_saving_limit=worth_saving_limit)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1807
        self._time_offset = 0
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1808
        self._log = []
2872.3.3 by Martin Pool
Fix up test_update_entry to work with -Dhashcache
1809
        # member is dynamically set in DirState.__init__ to turn on trace
4132.2.2 by Ian Clatworthy
make sha1_provider a mandatory param for DirState.__init__()
1810
        self._sha1_provider = sha1_provider
2872.3.3 by Martin Pool
Fix up test_update_entry to work with -Dhashcache
1811
        self._sha1_file = self._sha1_file_and_log
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1812
1813
    def _sha_cutoff_time(self):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1814
        timestamp = super(InstrumentedDirState, self)._sha_cutoff_time()
2255.10.6 by John Arbash Meinel
Save approx 30-60ms (5-10%) on a LP tree by not calling time.time() for every entry.
1815
        self._cutoff_time = timestamp + self._time_offset
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1816
2872.3.3 by Martin Pool
Fix up test_update_entry to work with -Dhashcache
1817
    def _sha1_file_and_log(self, abspath):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1818
        self._log.append(('sha1', abspath))
4132.2.2 by Ian Clatworthy
make sha1_provider a mandatory param for DirState.__init__()
1819
        return self._sha1_provider.sha1(abspath)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1820
1821
    def _read_link(self, abspath, old_link):
1822
        self._log.append(('read_link', abspath, old_link))
1823
        return super(InstrumentedDirState, self)._read_link(abspath, old_link)
1824
1825
    def _lstat(self, abspath, entry):
1826
        self._log.append(('lstat', abspath))
1827
        return super(InstrumentedDirState, self)._lstat(abspath, entry)
1828
1829
    def _is_executable(self, mode, old_executable):
1830
        self._log.append(('is_exec', mode, old_executable))
1831
        return super(InstrumentedDirState, self)._is_executable(mode,
1832
                                                                old_executable)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1833
1834
    def adjust_time(self, secs):
1835
        """Move the clock forward or back.
1836
1837
        :param secs: The amount to adjust the clock by. Positive values make it
1838
        seem as if we are in the future, negative values make it seem like we
1839
        are in the past.
1840
        """
1841
        self._time_offset += secs
2255.10.6 by John Arbash Meinel
Save approx 30-60ms (5-10%) on a LP tree by not calling time.time() for every entry.
1842
        self._cutoff_time = None
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1843
1844
1845
class _FakeStat(object):
1846
    """A class with the same attributes as a real stat result."""
1847
1848
    def __init__(self, size, mtime, ctime, dev, ino, mode):
1849
        self.st_size = size
1850
        self.st_mtime = mtime
1851
        self.st_ctime = ctime
1852
        self.st_dev = dev
1853
        self.st_ino = ino
1854
        self.st_mode = mode
1855
4132.2.3 by Ian Clatworthy
add test as suggested by poolie's review
1856
    @staticmethod
1857
    def from_stat(st):
1858
        return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
1859
            st.st_ino, st.st_mode)
1860
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1861
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
1862
class TestPackStat(tests.TestCaseWithTransport):
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1863
1864
    def assertPackStat(self, expected, stat_value):
1865
        """Check the packed and serialized form of a stat value."""
1866
        self.assertEqual(expected, dirstate.pack_stat(stat_value))
1867
1868
    def test_pack_stat_int(self):
1869
        st = _FakeStat(6859L, 1172758614, 1172758617, 777L, 6499538L, 0100644)
1870
        # Make sure that all parameters have an impact on the packed stat.
1871
        self.assertPackStat('AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
1872
        st.st_size = 7000L
1873
        #                ay0 => bWE
1874
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1875
        st.st_mtime = 1172758620
1876
        #                     4FZ => 4Fx
1877
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1878
        st.st_ctime = 1172758630
1879
        #                          uBZ => uBm
1880
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1881
        st.st_dev = 888L
1882
        #                                DCQ => DeA
1883
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
1884
        st.st_ino = 6499540L
1885
        #                                     LNI => LNQ
1886
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
1887
        st.st_mode = 0100744
1888
        #                                          IGk => IHk
1889
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
1890
1891
    def test_pack_stat_float(self):
1892
        """On some platforms mtime and ctime are floats.
1893
1894
        Make sure we don't get warnings or errors, and that we ignore changes <
1895
        1s
1896
        """
1897
        st = _FakeStat(7000L, 1172758614.0, 1172758617.0,
1898
                       777L, 6499538L, 0100644)
1899
        # These should all be the same as the integer counterparts
1900
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1901
        st.st_mtime = 1172758620.0
1902
        #                     FZF5 => FxF5
1903
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1904
        st.st_ctime = 1172758630.0
1905
        #                          uBZ => uBm
1906
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1907
        # fractional seconds are discarded, so no change from above
1908
        st.st_mtime = 1172758620.453
1909
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1910
        st.st_ctime = 1172758630.228
1911
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1912
1913
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
1914
class TestBisect(TestCaseWithDirState):
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1915
    """Test the ability to bisect into the disk format."""
1916
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1917
    def assertBisect(self, expected_map, map_keys, state, paths):
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1918
        """Assert that bisecting for paths returns the right result.
1919
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1920
        :param expected_map: A map from key => entry value
1921
        :param map_keys: The keys to expect for each path
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1922
        :param state: The DirState object.
1923
        :param paths: A list of paths, these will automatically be split into
1924
                      (dir, name) tuples, and sorted according to how _bisect
1925
                      requires.
1926
        """
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
1927
        result = state._bisect(paths)
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1928
        # For now, results are just returned in whatever order we read them.
1929
        # We could sort by (dir, name, file_id) or something like that, but in
1930
        # the end it would still be fairly arbitrary, and we don't want the
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1931
        # extra overhead if we can avoid it. So sort everything to make sure
1932
        # equality is true
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
1933
        self.assertEqual(len(map_keys), len(paths))
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1934
        expected = {}
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
1935
        for path, keys in zip(paths, map_keys):
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1936
            if keys is None:
1937
                # This should not be present in the output
1938
                continue
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
1939
            expected[path] = sorted(expected_map[k] for k in keys)
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1940
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
1941
        # The returned values are just arranged randomly based on when they
1942
        # were read, for testing, make sure it is properly sorted.
1943
        for path in result:
1944
            result[path].sort()
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1945
1946
        self.assertEqual(expected, result)
1947
1948
    def assertBisectDirBlocks(self, expected_map, map_keys, state, paths):
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
1949
        """Assert that bisecting for dirbblocks returns the right result.
1950
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1951
        :param expected_map: A map from key => expected values
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1952
        :param map_keys: A nested list of paths we expect to be returned.
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
1953
            Something like [['a', 'b', 'f'], ['b/c', 'b/d']]
1954
        :param state: The DirState object.
1955
        :param paths: A list of directories
1956
        """
1957
        result = state._bisect_dirblocks(paths)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
1958
        self.assertEqual(len(map_keys), len(paths))
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1959
        expected = {}
1960
        for path, keys in zip(paths, map_keys):
1961
            if keys is None:
1962
                # This should not be present in the output
1963
                continue
1964
            expected[path] = sorted(expected_map[k] for k in keys)
1965
        for path in result:
1966
            result[path].sort()
1967
1968
        self.assertEqual(expected, result)
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
1969
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1970
    def assertBisectRecursive(self, expected_map, map_keys, state, paths):
1971
        """Assert the return value of a recursive bisection.
1972
1973
        :param expected_map: A map from key => entry value
1974
        :param map_keys: A list of paths we expect to be returned.
1975
            Something like ['a', 'b', 'f', 'b/d', 'b/d2']
1976
        :param state: The DirState object.
1977
        :param paths: A list of files and directories. It will be broken up
1978
            into (dir, name) pairs and sorted before calling _bisect_recursive.
1979
        """
1980
        expected = {}
1981
        for key in map_keys:
1982
            entry = expected_map[key]
1983
            dir_name_id, trees_info = entry
1984
            expected[dir_name_id] = trees_info
1985
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
1986
        result = state._bisect_recursive(paths)
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1987
1988
        self.assertEqual(expected, result)
1989
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1990
    def test_bisect_each(self):
1991
        """Find a single record using bisect."""
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1992
        tree, state, expected = self.create_basic_dirstate()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1993
1994
        # Bisect should return the rows for the specified files.
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1995
        self.assertBisect(expected, [['']], state, [''])
1996
        self.assertBisect(expected, [['a']], state, ['a'])
1997
        self.assertBisect(expected, [['b']], state, ['b'])
1998
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1999
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
2000
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2001
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2002
        self.assertBisect(expected, [['f']], state, ['f'])
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
2003
2004
    def test_bisect_multi(self):
2005
        """Bisect can be used to find multiple records at the same time."""
2006
        tree, state, expected = self.create_basic_dirstate()
2007
        # Bisect should be capable of finding multiple entries at the same time
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2008
        self.assertBisect(expected, [['a'], ['b'], ['f']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2009
                          state, ['a', 'b', 'f'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2010
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
2474.1.61 by John Arbash Meinel
Finish fixing DirState._bisect and the bisect tests
2011
                          state, ['f', 'b/d', 'b/d/e'])
2012
        self.assertBisect(expected, [['b'], ['b-c'], ['b/c']],
2013
                          state, ['b', 'b-c', 'b/c'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2014
2015
    def test_bisect_one_page(self):
2016
        """Test bisect when there is only 1 page to read"""
2017
        tree, state, expected = self.create_basic_dirstate()
2018
        state._bisect_page_size = 5000
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2019
        self.assertBisect(expected,[['']], state, [''])
2020
        self.assertBisect(expected,[['a']], state, ['a'])
2021
        self.assertBisect(expected,[['b']], state, ['b'])
2022
        self.assertBisect(expected,[['b/c']], state, ['b/c'])
2023
        self.assertBisect(expected,[['b/d']], state, ['b/d'])
2024
        self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2025
        self.assertBisect(expected,[['b-c']], state, ['b-c'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2026
        self.assertBisect(expected,[['f']], state, ['f'])
2027
        self.assertBisect(expected,[['a'], ['b'], ['f']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2028
                          state, ['a', 'b', 'f'])
2474.1.61 by John Arbash Meinel
Finish fixing DirState._bisect and the bisect tests
2029
        self.assertBisect(expected, [['b/d'], ['b/d/e'], ['f']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2030
                          state, ['b/d', 'b/d/e', 'f'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2031
        self.assertBisect(expected, [['b'], ['b/c'], ['b-c']],
2032
                          state, ['b', 'b/c', 'b-c'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2033
2034
    def test_bisect_duplicate_paths(self):
2035
        """When bisecting for a path, handle multiple entries."""
2036
        tree, state, expected = self.create_duplicated_dirstate()
2037
2038
        # Now make sure that both records are properly returned.
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2039
        self.assertBisect(expected, [['']], state, [''])
2040
        self.assertBisect(expected, [['a', 'a2']], state, ['a'])
2041
        self.assertBisect(expected, [['b', 'b2']], state, ['b'])
2042
        self.assertBisect(expected, [['b/c', 'b/c2']], state, ['b/c'])
2043
        self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
2044
        self.assertBisect(expected, [['b/d/e', 'b/d/e2']],
2255.2.129 by John Arbash Meinel
Start cleaning up the code, and fix one more edge case
2045
                          state, ['b/d/e'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2046
        self.assertBisect(expected, [['b-c', 'b-c2']], state, ['b-c'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2047
        self.assertBisect(expected, [['f', 'f2']], state, ['f'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2048
2049
    def test_bisect_page_size_too_small(self):
2255.2.128 by John Arbash Meinel
Rather than falling over when the page size is to small, just increase it and try again.
2050
        """If the page size is too small, we will auto increase it."""
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2051
        tree, state, expected = self.create_basic_dirstate()
2052
        state._bisect_page_size = 50
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2053
        self.assertBisect(expected, [None], state, ['b/e'])
2054
        self.assertBisect(expected, [['a']], state, ['a'])
2055
        self.assertBisect(expected, [['b']], state, ['b'])
2056
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
2057
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
2058
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2059
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2060
        self.assertBisect(expected, [['f']], state, ['f'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2061
2062
    def test_bisect_missing(self):
2063
        """Test that bisect return None if it cannot find a path."""
2064
        tree, state, expected = self.create_basic_dirstate()
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2065
        self.assertBisect(expected, [None], state, ['foo'])
2066
        self.assertBisect(expected, [None], state, ['b/foo'])
2067
        self.assertBisect(expected, [None], state, ['bar/foo'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2068
        self.assertBisect(expected, [None], state, ['b-c/foo'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2069
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2070
        self.assertBisect(expected, [['a'], None, ['b/d']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
2071
                          state, ['a', 'foo', 'b/d'])
2255.2.127 by John Arbash Meinel
Expand the test suite to cover more cases.
2072
2073
    def test_bisect_rename(self):
2074
        """Check that we find a renamed row."""
2075
        tree, state, expected = self.create_renamed_dirstate()
2076
2077
        # Search for the pre and post renamed entries
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
2078
        self.assertBisect(expected, [['a']], state, ['a'])
2079
        self.assertBisect(expected, [['b/g']], state, ['b/g'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
2080
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
2081
        self.assertBisect(expected, [['h']], state, ['h'])
2082
2083
        # What about b/d/e? shouldn't that also get 2 directory entries?
2084
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
2085
        self.assertBisect(expected, [['h/e']], state, ['h/e'])
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
2086
2087
    def test_bisect_dirblocks(self):
2088
        tree, state, expected = self.create_duplicated_dirstate()
2089
        self.assertBisectDirBlocks(expected,
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2090
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2']],
2091
            state, [''])
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
2092
        self.assertBisectDirBlocks(expected,
2093
            [['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
2094
        self.assertBisectDirBlocks(expected,
2095
            [['b/d/e', 'b/d/e2']], state, ['b/d'])
2096
        self.assertBisectDirBlocks(expected,
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2097
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2'],
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
2098
             ['b/c', 'b/c2', 'b/d', 'b/d2'],
2099
             ['b/d/e', 'b/d/e2'],
2100
            ], state, ['', 'b', 'b/d'])
2101
2102
    def test_bisect_dirblocks_missing(self):
2103
        tree, state, expected = self.create_basic_dirstate()
2104
        self.assertBisectDirBlocks(expected, [['b/d/e'], None],
2105
            state, ['b/d', 'b/e'])
2106
        # Files don't show up in this search
2107
        self.assertBisectDirBlocks(expected, [None], state, ['a'])
2108
        self.assertBisectDirBlocks(expected, [None], state, ['b/c'])
2109
        self.assertBisectDirBlocks(expected, [None], state, ['c'])
2110
        self.assertBisectDirBlocks(expected, [None], state, ['b/d/e'])
2111
        self.assertBisectDirBlocks(expected, [None], state, ['f'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
2112
2113
    def test_bisect_recursive_each(self):
2114
        tree, state, expected = self.create_basic_dirstate()
2115
        self.assertBisectRecursive(expected, ['a'], state, ['a'])
2116
        self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
2117
        self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
2118
        self.assertBisectRecursive(expected, ['b-c'], state, ['b-c'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
2119
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2120
                                   state, ['b/d'])
2121
        self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
2122
                                   state, ['b'])
2474.1.61 by John Arbash Meinel
Finish fixing DirState._bisect and the bisect tests
2123
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'b-c', 'f', 'b/c',
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
2124
                                              'b/d', 'b/d/e'],
2125
                                   state, [''])
2126
2127
    def test_bisect_recursive_multiple(self):
2128
        tree, state, expected = self.create_basic_dirstate()
2129
        self.assertBisectRecursive(expected, ['a', 'b/c'], state, ['a', 'b/c'])
2130
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2131
                                   state, ['b/d', 'b/d/e'])
2132
2133
    def test_bisect_recursive_missing(self):
2134
        tree, state, expected = self.create_basic_dirstate()
2135
        self.assertBisectRecursive(expected, [], state, ['d'])
2136
        self.assertBisectRecursive(expected, [], state, ['b/e'])
2137
        self.assertBisectRecursive(expected, [], state, ['g'])
2138
        self.assertBisectRecursive(expected, ['a'], state, ['a', 'g'])
2139
2140
    def test_bisect_recursive_renamed(self):
2141
        tree, state, expected = self.create_renamed_dirstate()
2142
2143
        # Looking for either renamed item should find the other
2144
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
2145
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
2146
        # Looking in the containing directory should find the rename target,
2147
        # and anything in a subdir of the renamed target.
2148
        self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
2149
                                              'b/d/e', 'b/g', 'h', 'h/e'],
2150
                                   state, ['b'])
2151
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2152
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
2153
class TestDirstateValidation(TestCaseWithDirState):
2154
2155
    def test_validate_correct_dirstate(self):
2156
        state = self.create_complex_dirstate()
2157
        state._validate()
2158
        state.unlock()
2159
        # and make sure we can also validate with a read lock
2160
        state.lock_read()
2161
        try:
2162
            state._validate()
2163
        finally:
2164
            state.unlock()
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2165
2166
    def test_dirblock_not_sorted(self):
2167
        tree, state, expected = self.create_renamed_dirstate()
2168
        state._read_dirblocks_if_needed()
2169
        last_dirblock = state._dirblocks[-1]
2170
        # we're appending to the dirblock, but this name comes before some of
2171
        # the existing names; that's wrong
2172
        last_dirblock[1].append(
2173
            (('h', 'aaaa', 'a-id'),
2174
             [('a', '', 0, False, ''),
2175
              ('a', '', 0, False, '')]))
2176
        e = self.assertRaises(AssertionError,
2177
            state._validate)
2178
        self.assertContainsRe(str(e), 'not sorted')
2179
2180
    def test_dirblock_name_mismatch(self):
2181
        tree, state, expected = self.create_renamed_dirstate()
2182
        state._read_dirblocks_if_needed()
2183
        last_dirblock = state._dirblocks[-1]
2184
        # add an entry with the wrong directory name
2185
        last_dirblock[1].append(
2186
            (('', 'z', 'a-id'),
2187
             [('a', '', 0, False, ''),
2188
              ('a', '', 0, False, '')]))
2189
        e = self.assertRaises(AssertionError,
2190
            state._validate)
2191
        self.assertContainsRe(str(e),
2192
            "doesn't match directory name")
2193
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2194
    def test_dirblock_missing_rename(self):
2195
        tree, state, expected = self.create_renamed_dirstate()
2196
        state._read_dirblocks_if_needed()
2197
        last_dirblock = state._dirblocks[-1]
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2198
        # make another entry for a-id, without a correct 'r' pointer to
2199
        # the real occurrence in the working tree
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2200
        last_dirblock[1].append(
2201
            (('h', 'z', 'a-id'),
2202
             [('a', '', 0, False, ''),
2203
              ('a', '', 0, False, '')]))
2204
        e = self.assertRaises(AssertionError,
2205
            state._validate)
2206
        self.assertContainsRe(str(e),
2207
            'file a-id is absent in row')
2474.1.41 by John Arbash Meinel
Change the name of cmp_dirblock_strings to cmp_by_dirs
2208
2645.2.1 by Wouter van Heyst
The DirState fingerprint for tree-references should be an empty string instead of None
2209
2210
class TestDirstateTreeReference(TestCaseWithDirState):
2211
2212
    def test_reference_revision_is_none(self):
2213
        tree = self.make_branch_and_tree('tree', format='dirstate-with-subtree')
2214
        subtree = self.make_branch_and_tree('tree/subtree',
2215
                            format='dirstate-with-subtree')
2216
        subtree.set_root_id('subtree')
2217
        tree.add_reference(subtree)
2218
        tree.add('subtree')
2219
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2220
        key = ('', 'subtree', 'subtree')
2221
        expected = ('', [(key,
2222
            [('t', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])])
2223
2224
        try:
2225
            self.assertEqual(expected, state._find_block(key))
2226
        finally:
2227
            state.unlock()
2984.1.1 by John Arbash Meinel
Fix bug #161131: Correct DirState._discard_merge_parents logic.
2228
2229
2230
class TestDiscardMergeParents(TestCaseWithDirState):
2231
2232
    def test_discard_no_parents(self):
2233
        # This should be a no-op
2234
        state = self.create_empty_dirstate()
2235
        self.addCleanup(state.unlock)
2236
        state._discard_merge_parents()
2237
        state._validate()
2238
2239
    def test_discard_one_parent(self):
2240
        # No-op
2241
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2242
        root_entry_direntry = ('', '', 'a-root-value'), [
2243
            ('d', '', 0, False, packed_stat),
2244
            ('d', '', 0, False, packed_stat),
2245
            ]
2246
        dirblocks = []
2247
        dirblocks.append(('', [root_entry_direntry]))
2248
        dirblocks.append(('', []))
2249
2250
        state = self.create_empty_dirstate()
2251
        self.addCleanup(state.unlock)
2252
        state._set_data(['parent-id'], dirblocks[:])
2253
        state._validate()
2254
2255
        state._discard_merge_parents()
2256
        state._validate()
2257
        self.assertEqual(dirblocks, state._dirblocks)
2258
2259
    def test_discard_simple(self):
2260
        # No-op
2261
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2262
        root_entry_direntry = ('', '', 'a-root-value'), [
2263
            ('d', '', 0, False, packed_stat),
2264
            ('d', '', 0, False, packed_stat),
2265
            ('d', '', 0, False, packed_stat),
2266
            ]
2267
        expected_root_entry_direntry = ('', '', 'a-root-value'), [
2268
            ('d', '', 0, False, packed_stat),
2269
            ('d', '', 0, False, packed_stat),
2270
            ]
2271
        dirblocks = []
2272
        dirblocks.append(('', [root_entry_direntry]))
2273
        dirblocks.append(('', []))
2274
2275
        state = self.create_empty_dirstate()
2276
        self.addCleanup(state.unlock)
2277
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2278
        state._validate()
2279
2280
        # This should strip of the extra column
2281
        state._discard_merge_parents()
2282
        state._validate()
2283
        expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2284
        self.assertEqual(expected_dirblocks, state._dirblocks)
2285
2286
    def test_discard_absent(self):
2287
        """If entries are only in a merge, discard should remove the entries"""
2288
        null_stat = dirstate.DirState.NULLSTAT
2289
        present_dir = ('d', '', 0, False, null_stat)
2290
        present_file = ('f', '', 0, False, null_stat)
2291
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2292
        root_key = ('', '', 'a-root-value')
2293
        file_in_root_key = ('', 'file-in-root', 'a-file-id')
2294
        file_in_merged_key = ('', 'file-in-merged', 'b-file-id')
2295
        dirblocks = [('', [(root_key, [present_dir, present_dir, present_dir])]),
2296
                     ('', [(file_in_merged_key,
2297
                            [absent, absent, present_file]),
2298
                           (file_in_root_key,
2299
                            [present_file, present_file, present_file]),
2300
                          ]),
2301
                    ]
2302
2303
        state = self.create_empty_dirstate()
2304
        self.addCleanup(state.unlock)
2305
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2306
        state._validate()
2307
2308
        exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
2309
                         ('', [(file_in_root_key,
2310
                                [present_file, present_file]),
2311
                              ]),
2312
                        ]
2313
        state._discard_merge_parents()
2314
        state._validate()
2315
        self.assertEqual(exp_dirblocks, state._dirblocks)
2316
2317
    def test_discard_renamed(self):
2318
        null_stat = dirstate.DirState.NULLSTAT
2319
        present_dir = ('d', '', 0, False, null_stat)
2320
        present_file = ('f', '', 0, False, null_stat)
2321
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2322
        root_key = ('', '', 'a-root-value')
2323
        file_in_root_key = ('', 'file-in-root', 'a-file-id')
2324
        # Renamed relative to parent
2325
        file_rename_s_key = ('', 'file-s', 'b-file-id')
2326
        file_rename_t_key = ('', 'file-t', 'b-file-id')
2327
        # And one that is renamed between the parents, but absent in this
2328
        key_in_1 = ('', 'file-in-1', 'c-file-id')
2329
        key_in_2 = ('', 'file-in-2', 'c-file-id')
2330
2331
        dirblocks = [
2332
            ('', [(root_key, [present_dir, present_dir, present_dir])]),
2333
            ('', [(key_in_1,
2334
                   [absent, present_file, ('r', 'file-in-2', 'c-file-id')]),
2335
                  (key_in_2,
2336
                   [absent, ('r', 'file-in-1', 'c-file-id'), present_file]),
2337
                  (file_in_root_key,
2338
                   [present_file, present_file, present_file]),
2339
                  (file_rename_s_key,
2340
                   [('r', 'file-t', 'b-file-id'), absent, present_file]),
2341
                  (file_rename_t_key,
2342
                   [present_file, absent, ('r', 'file-s', 'b-file-id')]),
2343
                 ]),
2344
        ]
2345
        exp_dirblocks = [
2346
            ('', [(root_key, [present_dir, present_dir])]),
2347
            ('', [(key_in_1, [absent, present_file]),
2348
                  (file_in_root_key, [present_file, present_file]),
2349
                  (file_rename_t_key, [present_file, absent]),
2350
                 ]),
2351
        ]
2352
        state = self.create_empty_dirstate()
2353
        self.addCleanup(state.unlock)
2354
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2355
        state._validate()
2356
2357
        state._discard_merge_parents()
2358
        state._validate()
2359
        self.assertEqual(exp_dirblocks, state._dirblocks)
2360
2361
    def test_discard_all_subdir(self):
2362
        null_stat = dirstate.DirState.NULLSTAT
2363
        present_dir = ('d', '', 0, False, null_stat)
2364
        present_file = ('f', '', 0, False, null_stat)
2365
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2366
        root_key = ('', '', 'a-root-value')
2367
        subdir_key = ('', 'sub', 'dir-id')
2368
        child1_key = ('sub', 'child1', 'child1-id')
2369
        child2_key = ('sub', 'child2', 'child2-id')
2370
        child3_key = ('sub', 'child3', 'child3-id')
2371
2372
        dirblocks = [
2373
            ('', [(root_key, [present_dir, present_dir, present_dir])]),
2374
            ('', [(subdir_key, [present_dir, present_dir, present_dir])]),
2375
            ('sub', [(child1_key, [absent, absent, present_file]),
2376
                     (child2_key, [absent, absent, present_file]),
2377
                     (child3_key, [absent, absent, present_file]),
2378
                    ]),
2379
        ]
2380
        exp_dirblocks = [
2381
            ('', [(root_key, [present_dir, present_dir])]),
2382
            ('', [(subdir_key, [present_dir, present_dir])]),
2383
            ('sub', []),
2384
        ]
2385
        state = self.create_empty_dirstate()
2386
        self.addCleanup(state.unlock)
2387
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2388
        state._validate()
2389
2390
        state._discard_merge_parents()
2391
        state._validate()
2392
        self.assertEqual(exp_dirblocks, state._dirblocks)
3477.2.1 by John Arbash Meinel
Assert that we properly encode inv_entry.symlink_target, (bug #135320)
2393
2394
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
2395
class Test_InvEntryToDetails(tests.TestCase):
3477.2.1 by John Arbash Meinel
Assert that we properly encode inv_entry.symlink_target, (bug #135320)
2396
2397
    def assertDetails(self, expected, inv_entry):
2398
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
2399
        self.assertEqual(expected, details)
3477.2.2 by John Arbash Meinel
Change how we handle unicode targets, and add a NEWS entry.
2400
        # details should always allow join() and always be a plain str when
2401
        # finished
2402
        (minikind, fingerprint, size, executable, tree_data) = details
2403
        self.assertIsInstance(minikind, str)
2404
        self.assertIsInstance(fingerprint, str)
2405
        self.assertIsInstance(tree_data, str)
3477.2.1 by John Arbash Meinel
Assert that we properly encode inv_entry.symlink_target, (bug #135320)
2406
2407
    def test_unicode_symlink(self):
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
2408
        inv_entry = inventory.InventoryLink('link-file-id',
2409
                                            u'nam\N{Euro Sign}e',
3477.2.1 by John Arbash Meinel
Assert that we properly encode inv_entry.symlink_target, (bug #135320)
2410
                                            'link-parent-id')
2411
        inv_entry.revision = 'link-revision-id'
4241.14.10 by Vincent Ladeuil
Add DirReader parametrized tests.
2412
        target = u'link-targ\N{Euro Sign}t'
2413
        inv_entry.symlink_target = target
2414
        self.assertDetails(('l', target.encode('UTF-8'), 0, False,
2415
                            'link-revision-id'), inv_entry)
2416
2417
2418
class TestSHA1Provider(tests.TestCaseInTempDir):
4132.2.1 by Ian Clatworthy
make sha1_provider a parameter to DirState()
2419
2420
    def test_sha1provider_is_an_interface(self):
4132.2.5 by Ian Clatworthy
feedback from poolie - use SHA, not Sha, in class names
2421
        p = dirstate.SHA1Provider()
4132.2.1 by Ian Clatworthy
make sha1_provider a parameter to DirState()
2422
        self.assertRaises(NotImplementedError, p.sha1, "foo")
2423
        self.assertRaises(NotImplementedError, p.stat_and_sha1, "foo")
2424
2425
    def test_defaultsha1provider_sha1(self):
2426
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
2427
        self.build_tree_contents([('foo', text)])
2428
        expected_sha = osutils.sha_string(text)
4132.2.5 by Ian Clatworthy
feedback from poolie - use SHA, not Sha, in class names
2429
        p = dirstate.DefaultSHA1Provider()
4132.2.1 by Ian Clatworthy
make sha1_provider a parameter to DirState()
2430
        self.assertEqual(expected_sha, p.sha1('foo'))
2431
2432
    def test_defaultsha1provider_stat_and_sha1(self):
2433
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
2434
        self.build_tree_contents([('foo', text)])
2435
        expected_sha = osutils.sha_string(text)
4132.2.5 by Ian Clatworthy
feedback from poolie - use SHA, not Sha, in class names
2436
        p = dirstate.DefaultSHA1Provider()
4132.2.1 by Ian Clatworthy
make sha1_provider a parameter to DirState()
2437
        statvalue, sha1 = p.stat_and_sha1('foo')
2438
        self.assertTrue(len(statvalue) >= 10)
2439
        self.assertEqual(len(text), statvalue.st_size)
2440
        self.assertEqual(expected_sha, sha1)
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2441
2442
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
2443
class _Repo(object):
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2444
    """A minimal api to get InventoryRevisionTree to work."""
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
2445
2446
    def __init__(self):
2447
        default_format = bzrdir.format_registry.make_bzrdir('default')
2448
        self._format = default_format.repository_format
2449
2450
    def lock_read(self):
2451
        pass
2452
2453
    def unlock(self):
2454
        pass
2455
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2456
2457
class TestUpdateBasisByDelta(tests.TestCase):
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2458
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2459
    def path_to_ie(self, path, file_id, rev_id, dir_ids):
2460
        if path.endswith('/'):
2461
            is_dir = True
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2462
            path = path[:-1]
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2463
        else:
2464
            is_dir = False
2465
        dirname, basename = osutils.split(path)
5847.4.27 by John Arbash Meinel
Handle missing parent, though bugs may still remain
2466
        try:
2467
            dir_id = dir_ids[dirname]
2468
        except KeyError:
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2469
            dir_id = osutils.basename(dirname) + '-id'
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2470
        if is_dir:
2471
            ie = inventory.InventoryDirectory(file_id, basename, dir_id)
5847.4.29 by John Arbash Meinel
Simplify a bit. Handle that when a directory is added, we need to add its block.
2472
            dir_ids[path] = file_id
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2473
        else:
2474
            ie = inventory.InventoryFile(file_id, basename, dir_id)
2475
            ie.text_size = 0
2476
            ie.text_sha1 = ''
2477
        ie.revision = rev_id
2478
        return ie
2479
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
2480
    def create_tree_from_shape(self, rev_id, shape):
2481
        dir_ids = {'': 'root-id'}
2482
        inv = inventory.Inventory('root-id', rev_id)
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2483
        for path, file_id in shape:
5847.4.32 by John Arbash Meinel
Update the test suite to handle root changes.
2484
            if path == '':
2485
                # Replace the root entry
2486
                del inv._byid[inv.root.file_id]
2487
                inv.root.file_id = file_id
2488
                inv._byid[file_id] = inv.root
2489
                dir_ids[''] = file_id
2490
                continue
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2491
            inv.add(self.path_to_ie(path, file_id, rev_id, dir_ids))
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
2492
        return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2493
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2494
    def create_empty_dirstate(self):
2495
        fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2496
        self.addCleanup(os.remove, path)
2497
        os.close(fd)
2498
        state = dirstate.DirState.initialize(path)
2499
        self.addCleanup(state.unlock)
2500
        return state
2501
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2502
    def create_inv_delta(self, delta, rev_id):
2503
        """Translate a 'delta shape' into an actual InventoryDelta"""
2504
        dir_ids = {'': 'root-id'}
2505
        inv_delta = []
2506
        for old_path, new_path, file_id in delta:
2507
            if old_path is not None and old_path.endswith('/'):
2508
                # Don't have to actually do anything for this, because only
2509
                # new_path creates InventoryEntries
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2510
                old_path = old_path[:-1]
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2511
            if new_path is None: # Delete
2512
                inv_delta.append((old_path, None, file_id, None))
2513
                continue
2514
            ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2515
            inv_delta.append((old_path, new_path, file_id, ie))
2516
        return inv_delta
2517
5847.4.15 by John Arbash Meinel
two simple tests in the new framework.
2518
    def assertUpdate(self, active, basis, target):
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2519
        """Assert that update_basis_by_delta works how we want.
2520
2521
        Set up a DirState object with active_shape for tree 0, basis_shape for
2522
        tree 1. Then apply the delta from basis_shape to target_shape,
2523
        and assert that the DirState is still valid, and that its stored
2524
        content matches the target_shape.
2525
        """
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2526
        active_tree = self.create_tree_from_shape('active', active)
2527
        basis_tree = self.create_tree_from_shape('basis', basis)
2528
        target_tree = self.create_tree_from_shape('target', target)
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2529
        state = self.create_empty_dirstate()
5847.4.15 by John Arbash Meinel
two simple tests in the new framework.
2530
        state.set_state_from_scratch(active_tree.inventory,
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2531
            [('basis', basis_tree)], [])
2532
        delta = target_tree.inventory._make_delta(basis_tree.inventory)
5847.4.15 by John Arbash Meinel
two simple tests in the new framework.
2533
        state.update_basis_by_delta(delta, 'target')
2534
        state._validate()
2535
        dirstate_tree = workingtree_4.DirStateRevisionTree(state,
5847.4.16 by John Arbash Meinel
Switching from BranchBuilder to Inventory directly dropped us from 73ms to 26ms.
2536
            'target', _Repo())
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2537
        # The target now that delta has been applied should match the
2538
        # RevisionTree
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2539
        self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2540
        # And the dirblock state should be identical to the state if we created
2541
        # it from scratch.
2542
        state2 = self.create_empty_dirstate()
2543
        state2.set_state_from_scratch(active_tree.inventory,
2544
            [('target', target_tree)], [])
5847.4.20 by John Arbash Meinel
Handle a bunch of rename cases.
2545
        self.assertEqual(state2._dirblocks, state._dirblocks)
5847.4.15 by John Arbash Meinel
two simple tests in the new framework.
2546
        return state
5847.4.14 by John Arbash Meinel
Create a direct helper for testing UpdateBasisByDelta cases.
2547
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2548
    def assertBadDelta(self, active, basis, delta):
2549
        """Test that we raise InconsistentDelta when appropriate.
2550
2551
        :param active: The active tree shape
2552
        :param basis: The basis tree shape
2553
        :param delta: A description of the delta to apply. Similar to the form
2554
            for regular inventory deltas, but omitting the InventoryEntry.
2555
            So adding a file is: (None, 'path', 'file-id')
2556
            Adding a directory is: (None, 'path/', 'dir-id')
2557
            Renaming a dir is: ('old/', 'new/', 'dir-id')
2558
            etc.
2559
        """
2560
        active_tree = self.create_tree_from_shape('active', active)
2561
        basis_tree = self.create_tree_from_shape('basis', basis)
2562
        inv_delta = self.create_inv_delta(delta, 'target')
2563
        state = self.create_empty_dirstate()
2564
        state.set_state_from_scratch(active_tree.inventory,
2565
            [('basis', basis_tree)], [])
5847.4.25 by John Arbash Meinel
Trap an InconsistentDelta case. add can try to add another
2566
        self.assertRaises(errors.InconsistentDelta,
2567
            state.update_basis_by_delta, inv_delta, 'target')
5847.4.26 by John Arbash Meinel
_check_delta_ids_absent thought it didn't have to set _changes_aborted=True
2568
        ## try:
2569
        ##     state.update_basis_by_delta(inv_delta, 'target')
2570
        ## except errors.InconsistentDelta, e:
2571
        ##     import pdb; pdb.set_trace()
2572
        ## else:
2573
        ##     import pdb; pdb.set_trace()
5847.4.22 by John Arbash Meinel
Cleanup dirstate a bit.
2574
        self.assertTrue(state._changes_aborted)
2575
5847.4.15 by John Arbash Meinel
two simple tests in the new framework.
2576
    def test_remove_file_matching_active_state(self):
2577
        state = self.assertUpdate(
2578
            active=[],
2579
            basis =[('file', 'file-id')],
2580
            target=[],
2581
            )
5847.4.17 by John Arbash Meinel
The 25ms was the time spent checking that we didn't alter the containing WT.
2582
2583
    def test_remove_file_present_in_active_state(self):
2584
        state = self.assertUpdate(
2585
            active=[('file', 'file-id')],
2586
            basis =[('file', 'file-id')],
2587
            target=[],
2588
            )
5847.4.18 by John Arbash Meinel
And now we add a bunch more tests, and finally have a failing case.
2589
2590
    def test_remove_file_present_elsewhere_in_active_state(self):
2591
        state = self.assertUpdate(
2592
            active=[('other-file', 'file-id')],
2593
            basis =[('file', 'file-id')],
2594
            target=[],
2595
            )
2596
2597
    def test_remove_file_active_state_has_diff_file(self):
2598
        state = self.assertUpdate(
2599
            active=[('file', 'file-id-2')],
2600
            basis =[('file', 'file-id')],
2601
            target=[],
2602
            )
2603
2604
    def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2605
        state = self.assertUpdate(
2606
            active=[('file', 'file-id-2'),
2607
                    ('other-file', 'file-id')],
2608
            basis =[('file', 'file-id')],
2609
            target=[],
2610
            )
2611
2612
    def test_add_file_matching_active_state(self):
2613
        state = self.assertUpdate(
2614
            active=[('file', 'file-id')],
2615
            basis =[],
2616
            target=[('file', 'file-id')],
2617
            )
2618
2619
    def test_add_file_missing_in_active_state(self):
2620
        state = self.assertUpdate(
2621
            active=[],
2622
            basis =[],
2623
            target=[('file', 'file-id')],
2624
            )
2625
2626
    def test_add_file_elsewhere_in_active_state(self):
2627
        state = self.assertUpdate(
2628
            active=[('other-file', 'file-id')],
2629
            basis =[],
2630
            target=[('file', 'file-id')],
2631
            )
5847.4.20 by John Arbash Meinel
Handle a bunch of rename cases.
2632
2633
    def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2634
        state = self.assertUpdate(
2635
            active=[('other-file', 'file-id'),
2636
                    ('file', 'file-id-2')],
2637
            basis =[],
2638
            target=[('file', 'file-id')],
2639
            )
2640
2641
    def test_rename_file_matching_active_state(self):
2642
        state = self.assertUpdate(
2643
            active=[('other-file', 'file-id')],
2644
            basis =[('file', 'file-id')],
2645
            target=[('other-file', 'file-id')],
2646
            )
2647
2648
    def test_rename_file_missing_in_active_state(self):
2649
        state = self.assertUpdate(
2650
            active=[],
2651
            basis =[('file', 'file-id')],
2652
            target=[('other-file', 'file-id')],
2653
            )
2654
2655
    def test_rename_file_present_elsewhere_in_active_state(self):
2656
        state = self.assertUpdate(
2657
            active=[('third', 'file-id')],
2658
            basis =[('file', 'file-id')],
2659
            target=[('other-file', 'file-id')],
2660
            )
2661
2662
    def test_rename_file_active_state_has_diff_source_file(self):
2663
        state = self.assertUpdate(
2664
            active=[('file', 'file-id-2')],
2665
            basis =[('file', 'file-id')],
2666
            target=[('other-file', 'file-id')],
2667
            )
2668
2669
    def test_rename_file_active_state_has_diff_target_file(self):
2670
        state = self.assertUpdate(
2671
            active=[('other-file', 'file-id-2')],
2672
            basis =[('file', 'file-id')],
2673
            target=[('other-file', 'file-id')],
2674
            )
5847.4.21 by John Arbash Meinel
We were raising exceptions improperly. A couple more tests cases, so far so good.
2675
2676
    def test_rename_file_active_has_swapped_files(self):
2677
        state = self.assertUpdate(
2678
            active=[('file', 'file-id'),
2679
                    ('other-file', 'file-id-2')],
2680
            basis= [('file', 'file-id'),
2681
                    ('other-file', 'file-id-2')],
2682
            target=[('file', 'file-id-2'),
2683
                    ('other-file', 'file-id')])
2684
2685
    def test_rename_file_basis_has_swapped_files(self):
2686
        state = self.assertUpdate(
2687
            active=[('file', 'file-id'),
2688
                    ('other-file', 'file-id-2')],
2689
            basis= [('file', 'file-id-2'),
2690
                    ('other-file', 'file-id')],
2691
            target=[('file', 'file-id'),
2692
                    ('other-file', 'file-id-2')])
5847.4.23 by John Arbash Meinel
Add the first invalid delta test.
2693
5847.4.29 by John Arbash Meinel
Simplify a bit. Handle that when a directory is added, we need to add its block.
2694
    def test_rename_directory_with_contents(self):
2695
        state = self.assertUpdate( # active matches basis
2696
            active=[('dir1/', 'dir-id'),
2697
                    ('dir1/file', 'file-id')],
2698
            basis= [('dir1/', 'dir-id'),
2699
                    ('dir1/file', 'file-id')],
2700
            target=[('dir2/', 'dir-id'),
2701
                    ('dir2/file', 'file-id')])
2702
        state = self.assertUpdate( # active matches target
2703
            active=[('dir2/', 'dir-id'),
2704
                    ('dir2/file', 'file-id')],
2705
            basis= [('dir1/', 'dir-id'),
2706
                    ('dir1/file', 'file-id')],
2707
            target=[('dir2/', 'dir-id'),
2708
                    ('dir2/file', 'file-id')])
2709
        state = self.assertUpdate( # active empty
2710
            active=[],
2711
            basis= [('dir1/', 'dir-id'),
2712
                    ('dir1/file', 'file-id')],
2713
            target=[('dir2/', 'dir-id'),
2714
                    ('dir2/file', 'file-id')])
2715
        state = self.assertUpdate( # active present at other location
2716
            active=[('dir3/', 'dir-id'),
2717
                    ('dir3/file', 'file-id')],
2718
            basis= [('dir1/', 'dir-id'),
2719
                    ('dir1/file', 'file-id')],
2720
            target=[('dir2/', 'dir-id'),
2721
                    ('dir2/file', 'file-id')])
2722
        state = self.assertUpdate( # active has different ids
2723
            active=[('dir1/', 'dir1-id'),
2724
                    ('dir1/file', 'file1-id'),
2725
                    ('dir2/', 'dir2-id'),
2726
                    ('dir2/file', 'file2-id')],
2727
            basis= [('dir1/', 'dir-id'),
2728
                    ('dir1/file', 'file-id')],
2729
            target=[('dir2/', 'dir-id'),
2730
                    ('dir2/file', 'file-id')])
2731
5847.4.23 by John Arbash Meinel
Add the first invalid delta test.
2732
    def test_invalid_file_not_present(self):
2733
        state = self.assertBadDelta(
2734
            active=[('file', 'file-id')],
2735
            basis= [('file', 'file-id')],
2736
            delta=[('other-file', 'file', 'file-id')])
2737
5847.4.24 by John Arbash Meinel
Start handling an InconsistentDelta case exposed by test_inv cases.
2738
    def test_invalid_new_id_same_path(self):
5847.4.25 by John Arbash Meinel
Trap an InconsistentDelta case. add can try to add another
2739
        # The bad entry comes after
5847.4.24 by John Arbash Meinel
Start handling an InconsistentDelta case exposed by test_inv cases.
2740
        state = self.assertBadDelta(
2741
            active=[('file', 'file-id')],
2742
            basis= [('file', 'file-id')],
2743
            delta=[(None, 'file', 'file-id-2')])
5847.4.25 by John Arbash Meinel
Trap an InconsistentDelta case. add can try to add another
2744
        # The bad entry comes first
2745
        state = self.assertBadDelta(
2746
            active=[('file', 'file-id-2')],
5847.4.27 by John Arbash Meinel
Handle missing parent, though bugs may still remain
2747
            basis=[('file', 'file-id-2')],
5847.4.25 by John Arbash Meinel
Trap an InconsistentDelta case. add can try to add another
2748
            delta=[(None, 'file', 'file-id')])
5847.4.24 by John Arbash Meinel
Start handling an InconsistentDelta case exposed by test_inv cases.
2749
5847.4.27 by John Arbash Meinel
Handle missing parent, though bugs may still remain
2750
    def test_invalid_existing_id(self):
5847.4.26 by John Arbash Meinel
_check_delta_ids_absent thought it didn't have to set _changes_aborted=True
2751
        state = self.assertBadDelta(
2752
            active=[('file', 'file-id')],
2753
            basis= [('file', 'file-id')],
2754
            delta=[(None, 'file', 'file-id')])
2755
5847.4.27 by John Arbash Meinel
Handle missing parent, though bugs may still remain
2756
    def test_invalid_parent_missing(self):
2757
        state = self.assertBadDelta(
2758
            active=[],
2759
            basis= [],
2760
            delta=[(None, 'path/path2', 'file-id')])
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2761
        # Note: we force the active tree to have the directory, by knowing how
2762
        #       path_to_ie handles entries with missing parents
2763
        state = self.assertBadDelta(
2764
            active=[('path/', 'path-id')],
5847.4.33 by John Arbash Meinel
Clean up the _update_basis_apply_changes code
2765
            basis= [],
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2766
            delta=[(None, 'path/path2', 'file-id')])
2767
        state = self.assertBadDelta(
2768
            active=[('path/', 'path-id'),
2769
                    ('path/path2', 'file-id')],
5847.4.33 by John Arbash Meinel
Clean up the _update_basis_apply_changes code
2770
            basis= [],
5847.4.28 by John Arbash Meinel
Some more direct tests. Fix some bugs in the create_entry code.
2771
            delta=[(None, 'path/path2', 'file-id')])
2772
5847.4.36 by John Arbash Meinel
test cases for stuff like a parent becoming its own parent,
2773
    def test_renamed_dir_same_path(self):
2774
        # We replace the parent directory, with another parent dir. But the C
2775
        # file doesn't look like it has been moved.
2776
        state = self.assertUpdate(# Same as basis
5847.4.38 by John Arbash Meinel
Removing the 'fast-path' for paths that look unchanged fixes the bug.
2777
            active=[('dir/', 'A-id'),
2778
                    ('dir/B', 'B-id')],
2779
            basis= [('dir/', 'A-id'),
2780
                    ('dir/B', 'B-id')],
2781
            target=[('dir/', 'C-id'),
2782
                    ('dir/B', 'B-id')])
2783
        state = self.assertUpdate(# Same as target
2784
            active=[('dir/', 'C-id'),
2785
                    ('dir/B', 'B-id')],
2786
            basis= [('dir/', 'A-id'),
2787
                    ('dir/B', 'B-id')],
2788
            target=[('dir/', 'C-id'),
2789
                    ('dir/B', 'B-id')])
2790
        state = self.assertUpdate(# empty active
2791
            active=[],
2792
            basis= [('dir/', 'A-id'),
2793
                    ('dir/B', 'B-id')],
2794
            target=[('dir/', 'C-id'),
2795
                    ('dir/B', 'B-id')])
2796
        state = self.assertUpdate(# different active
2797
            active=[('dir/', 'D-id'),
2798
                    ('dir/B', 'B-id')],
2799
            basis= [('dir/', 'A-id'),
2800
                    ('dir/B', 'B-id')],
2801
            target=[('dir/', 'C-id'),
2802
                    ('dir/B', 'B-id')])
5847.4.36 by John Arbash Meinel
test cases for stuff like a parent becoming its own parent,
2803
2804
    def test_parent_child_swap(self):
2805
        state = self.assertUpdate(# Same as basis
2806
            active=[('A/', 'A-id'),
2807
                    ('A/B/', 'B-id'),
2808
                    ('A/B/C', 'C-id')],
2809
            basis= [('A/', 'A-id'),
2810
                    ('A/B/', 'B-id'),
2811
                    ('A/B/C', 'C-id')],
2812
            target=[('A/', 'B-id'),
2813
                    ('A/B/', 'A-id'),
2814
                    ('A/B/C', 'C-id')])
2815
        state = self.assertUpdate(# Same as target
2816
            active=[('A/', 'B-id'),
2817
                    ('A/B/', 'A-id'),
2818
                    ('A/B/C', 'C-id')],
2819
            basis= [('A/', 'A-id'),
2820
                    ('A/B/', 'B-id'),
2821
                    ('A/B/C', 'C-id')],
2822
            target=[('A/', 'B-id'),
2823
                    ('A/B/', 'A-id'),
2824
                    ('A/B/C', 'C-id')])
2825
        state = self.assertUpdate(# empty active
2826
            active=[],
2827
            basis= [('A/', 'A-id'),
2828
                    ('A/B/', 'B-id'),
2829
                    ('A/B/C', 'C-id')],
2830
            target=[('A/', 'B-id'),
2831
                    ('A/B/', 'A-id'),
2832
                    ('A/B/C', 'C-id')])
2833
        state = self.assertUpdate(# different active
2834
            active=[('D/', 'A-id'),
2835
                    ('D/E/', 'B-id'),
2836
                    ('F', 'C-id')],
2837
            basis= [('A/', 'A-id'),
2838
                    ('A/B/', 'B-id'),
2839
                    ('A/B/C', 'C-id')],
2840
            target=[('A/', 'B-id'),
2841
                    ('A/B/', 'A-id'),
2842
                    ('A/B/C', 'C-id')])
2843
5847.4.32 by John Arbash Meinel
Update the test suite to handle root changes.
2844
    def test_change_root_id(self):
2845
        state = self.assertUpdate( # same as basis
2846
            active=[('', 'root-id'),
2847
                    ('file', 'file-id')],
2848
            basis= [('', 'root-id'),
2849
                    ('file', 'file-id')],
2850
            target=[('', 'target-root-id'),
2851
                    ('file', 'file-id')])
2852
        state = self.assertUpdate( # same as target
2853
            active=[('', 'target-root-id'),
2854
                    ('file', 'file-id')],
2855
            basis= [('', 'root-id'),
2856
                    ('file', 'file-id')],
2857
            target=[('', 'target-root-id'),
2858
                    ('file', 'root-id')])
2859
        state = self.assertUpdate( # all different
2860
            active=[('', 'active-root-id'),
2861
                    ('file', 'file-id')],
2862
            basis= [('', 'root-id'),
2863
                    ('file', 'file-id')],
2864
            target=[('', 'target-root-id'),
2865
                    ('file', 'root-id')])
5847.4.33 by John Arbash Meinel
Clean up the _update_basis_apply_changes code
2866
2867
    def test_change_file_absent_in_active(self):
2868
        state = self.assertUpdate(
2869
            active=[],
2870
            basis= [('file', 'file-id')],
2871
            target=[('file', 'file-id')])
2872
2873
    def test_invalid_changed_file(self):
2874
        state = self.assertBadDelta( # Not present in basis
2875
            active=[('file', 'file-id')],
2876
            basis= [],
2877
            delta=[('file', 'file', 'file-id')])
2878
        state = self.assertBadDelta( # present at another location in basis
2879
            active=[('file', 'file-id')],
2880
            basis= [('other-file', 'file-id')],
2881
            delta=[('file', 'file', 'file-id')])