/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.27 by John Arbash Meinel
Fix a copyright statement to let 'source' tests pass
1
# Copyright (C) 2006, 2007 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests of the dirstate functionality being built for WorkingTreeFormat4."""
18
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
19
import bisect
1852.13.20 by Robert Collins
Steps toward an object model.
20
import os
2255.10.7 by John Arbash Meinel
Some updates to how we handle the executable bit. In preparation for supporting Win32
21
import time
1852.13.20 by Robert Collins
Steps toward an object model.
22
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
23
from bzrlib import (
24
    dirstate,
25
    errors,
26
    osutils,
27
    )
2255.2.4 by Robert Collins
Snapshot dirstate development
28
from bzrlib.memorytree import MemoryTree
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
29
from bzrlib.osutils import has_symlinks
30
from bzrlib.tests import (
31
        TestCase,
32
        TestCaseWithTransport,
33
        TestSkipped,
34
        )
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
35
36
37
# TODO:
2255.2.4 by Robert Collins
Snapshot dirstate development
38
# 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.
39
# general checks for NOT_IN_MEMORY error conditions.
40
# set_path_id on a NOT_IN_MEMORY dirstate
2255.2.4 by Robert Collins
Snapshot dirstate development
41
# set_path_id  unicode support
42
# set_path_id  setting id of a path not root
43
# set_path_id  setting id when there are parents without the id in the parents
44
# set_path_id  setting id when there are parents with the id in the parents
45
# set_path_id  setting id when state is not in memory
46
# set_path_id  setting id when state is in memory unmodified
47
# set_path_id  setting id when state is in memory modified
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
48
2255.2.236 by Martin Pool
Review cleanups: mostly updating or removing todo comments.
49
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
50
class TestCaseWithDirState(TestCaseWithTransport):
51
    """Helper functions for creating DirState objects with various content."""
52
53
    def create_empty_dirstate(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
54
        """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.
55
        state = dirstate.DirState.initialize('dirstate')
56
        return state
57
58
    def create_dirstate_with_root(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
59
        """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.
60
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
61
        root_entry_direntry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
62
            ('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.
63
            ]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
64
        dirblocks = []
65
        dirblocks.append(('', [root_entry_direntry]))
66
        dirblocks.append(('', []))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
67
        state = self.create_empty_dirstate()
68
        try:
69
            state._set_data([], dirblocks)
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
70
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
71
        except:
72
            state.unlock()
73
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
74
        return state
75
76
    def create_dirstate_with_root_and_subdir(self):
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
77
        """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.
78
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
79
        subdir_entry = ('', 'subdir', 'subdir-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
80
            ('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.
81
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
82
        state = self.create_dirstate_with_root()
83
        try:
84
            dirblocks = list(state._dirblocks)
85
            dirblocks[1][1].append(subdir_entry)
86
            state._set_data([], dirblocks)
87
        except:
88
            state.unlock()
89
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
90
        return state
91
92
    def create_complex_dirstate(self):
93
        """This dirstate contains multiple files and directories.
94
95
         /        a-root-value
96
         a/       a-dir
97
         b/       b-dir
98
         c        c-file
99
         d        d-file
100
         a/e/     e-dir
101
         a/f      f-file
102
         b/g      g-file
103
         b/h\xc3\xa5  h-\xc3\xa5-file  #This is u'\xe5' encoded into utf-8
104
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
105
        Notice that a/e is an empty directory.
106
107
        :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.
108
        """
109
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
110
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
111
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
112
            ('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.
113
            ]
114
        a_entry = ('', 'a', 'a-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
115
            ('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.
116
            ]
117
        b_entry = ('', 'b', 'b-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
118
            ('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.
119
            ]
120
        c_entry = ('', 'c', 'c-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
121
            ('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.
122
            ]
123
        d_entry = ('', 'd', 'd-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
124
            ('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.
125
            ]
126
        e_entry = ('a', 'e', 'e-dir'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
127
            ('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.
128
            ]
129
        f_entry = ('a', 'f', 'f-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
130
            ('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.
131
            ]
132
        g_entry = ('b', 'g', 'g-file'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
133
            ('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.
134
            ]
135
        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
136
            ('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.
137
            ]
138
        dirblocks = []
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
139
        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.
140
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
141
        dirblocks.append(('a', [e_entry, f_entry]))
142
        dirblocks.append(('b', [g_entry, h_entry]))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
143
        state = dirstate.DirState.initialize('dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
144
        state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
145
        try:
146
            state._set_data([], dirblocks)
147
        except:
148
            state.unlock()
149
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
150
        return state
151
152
    def check_state_with_reopen(self, expected_result, state):
153
        """Check that state has current state expected_result.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
154
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
155
        This will check the current state, open the file anew and check it
156
        again.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
157
        This function expects the current state to be locked for writing, and
158
        will unlock it before re-opening.
159
        This is required because we can't open a lock_read() while something
160
        else has a lock_write().
161
            write => mutually exclusive lock
162
            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.
163
        """
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
164
        # The state should already be write locked, since we just had to do
165
        # some operation to get here.
166
        assert state._lock_token is not None
167
        try:
168
            self.assertEqual(expected_result[0],  state.get_parent_ids())
169
            # there should be no ghosts in this tree.
170
            self.assertEqual([], state.get_ghosts())
171
            # there should be one fileid in this tree - the root of the tree.
172
            self.assertEqual(expected_result[1], list(state._iter_entries()))
173
            state.save()
174
        finally:
175
            state.unlock()
176
        del state # Callers should unlock
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
177
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
178
        state.lock_read()
179
        try:
180
            self.assertEqual(expected_result[1], list(state._iter_entries()))
181
        finally:
182
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
183
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
184
    def create_basic_dirstate(self):
185
        """Create a dirstate with a few files and directories.
186
187
            a
188
            b/
189
              c
190
              d/
191
                e
192
            f
193
        """
194
        tree = self.make_branch_and_tree('tree')
195
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'f']
196
        file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id']
197
        self.build_tree(['tree/' + p for p in paths])
198
        tree.set_root_id('TREE_ROOT')
199
        tree.add([p.rstrip('/') for p in paths], file_ids)
200
        tree.commit('initial', rev_id='rev-1')
201
        revision_id = 'rev-1'
202
        # a_packed_stat = dirstate.pack_stat(os.stat('tree/a'))
203
        t = self.get_transport().clone('tree')
204
        a_text = t.get_bytes('a')
205
        a_sha = osutils.sha_string(a_text)
206
        a_len = len(a_text)
207
        # b_packed_stat = dirstate.pack_stat(os.stat('tree/b'))
208
        # c_packed_stat = dirstate.pack_stat(os.stat('tree/b/c'))
209
        c_text = t.get_bytes('b/c')
210
        c_sha = osutils.sha_string(c_text)
211
        c_len = len(c_text)
212
        # d_packed_stat = dirstate.pack_stat(os.stat('tree/b/d'))
213
        # e_packed_stat = dirstate.pack_stat(os.stat('tree/b/d/e'))
214
        e_text = t.get_bytes('b/d/e')
215
        e_sha = osutils.sha_string(e_text)
216
        e_len = len(e_text)
217
        # f_packed_stat = dirstate.pack_stat(os.stat('tree/f'))
218
        f_text = t.get_bytes('f')
219
        f_sha = osutils.sha_string(f_text)
220
        f_len = len(f_text)
221
        null_stat = dirstate.DirState.NULLSTAT
222
        expected = {
223
            '':(('', '', 'TREE_ROOT'), [
224
                  ('d', '', 0, False, null_stat),
225
                  ('d', '', 0, False, revision_id),
226
                ]),
227
            'a':(('', 'a', 'a-id'), [
228
                   ('f', '', 0, False, null_stat),
229
                   ('f', a_sha, a_len, False, revision_id),
230
                 ]),
231
            'b':(('', 'b', 'b-id'), [
232
                  ('d', '', 0, False, null_stat),
233
                  ('d', '', 0, False, revision_id),
234
                 ]),
235
            'b/c':(('b', 'c', 'c-id'), [
236
                    ('f', '', 0, False, null_stat),
237
                    ('f', c_sha, c_len, False, revision_id),
238
                   ]),
239
            'b/d':(('b', 'd', 'd-id'), [
240
                    ('d', '', 0, False, null_stat),
241
                    ('d', '', 0, False, revision_id),
242
                   ]),
243
            'b/d/e':(('b/d', 'e', 'e-id'), [
244
                      ('f', '', 0, False, null_stat),
245
                      ('f', e_sha, e_len, False, revision_id),
246
                     ]),
247
            'f':(('', 'f', 'f-id'), [
248
                  ('f', '', 0, False, null_stat),
249
                  ('f', f_sha, f_len, False, revision_id),
250
                 ]),
251
        }
252
        state = dirstate.DirState.from_tree(tree, 'dirstate')
253
        try:
254
            state.save()
255
        finally:
256
            state.unlock()
257
        # Use a different object, to make sure nothing is pre-cached in memory.
258
        state = dirstate.DirState.on_file('dirstate')
259
        state.lock_read()
260
        self.addCleanup(state.unlock)
261
        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
262
                         state._dirblock_state)
263
        # This is code is only really tested if we actually have to make more
264
        # than one read, so set the page size to something smaller.
265
        # We want it to contain about 2.2 records, so that we have a couple
266
        # records that we can read per attempt
267
        state._bisect_page_size = 200
268
        return tree, state, expected
269
270
    def create_duplicated_dirstate(self):
271
        """Create a dirstate with a deleted and added entries.
272
273
        This grabs a basic_dirstate, and then removes and re adds every entry
274
        with a new file id.
275
        """
276
        tree, state, expected = self.create_basic_dirstate()
277
        # Now we will just remove and add every file so we get an extra entry
278
        # per entry. Unversion in reverse order so we handle subdirs
279
        tree.unversion(['f-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
280
        tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f'],
281
                 ['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'f-id2'])
282
283
        # Update the expected dictionary.
284
        for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f']:
285
            orig = expected[path]
286
            path2 = path + '2'
287
            # This record was deleted in the current tree
288
            expected[path] = (orig[0], [dirstate.DirState.NULL_PARENT_DETAILS,
289
                                        orig[1][1]])
290
            new_key = (orig[0][0], orig[0][1], orig[0][2]+'2')
291
            # And didn't exist in the basis tree
292
            expected[path2] = (new_key, [orig[1][0],
293
                                         dirstate.DirState.NULL_PARENT_DETAILS])
294
295
        # We will replace the 'dirstate' file underneath 'state', but that is
296
        # okay as lock as we unlock 'state' first.
297
        state.unlock()
298
        try:
299
            new_state = dirstate.DirState.from_tree(tree, 'dirstate')
300
            try:
301
                new_state.save()
302
            finally:
303
                new_state.unlock()
304
        finally:
305
            # But we need to leave state in a read-lock because we already have
306
            # a cleanup scheduled
307
            state.lock_read()
308
        return tree, state, expected
309
310
    def create_renamed_dirstate(self):
311
        """Create a dirstate with a few internal renames.
312
313
        This takes the basic dirstate, and moves the paths around.
314
        """
315
        tree, state, expected = self.create_basic_dirstate()
316
        # Rename a file
317
        tree.rename_one('a', 'b/g')
318
        # And a directory
319
        tree.rename_one('b/d', 'h')
320
321
        old_a = expected['a']
322
        expected['a'] = (old_a[0], [('r', 'b/g', 0, False, ''), old_a[1][1]])
323
        expected['b/g'] = (('b', 'g', 'a-id'), [old_a[1][0],
324
                                                ('r', 'a', 0, False, '')])
325
        old_d = expected['b/d']
326
        expected['b/d'] = (old_d[0], [('r', 'h', 0, False, ''), old_d[1][1]])
327
        expected['h'] = (('', 'h', 'd-id'), [old_d[1][0],
328
                                             ('r', 'b/d', 0, False, '')])
329
330
        old_e = expected['b/d/e']
331
        expected['b/d/e'] = (old_e[0], [('r', 'h/e', 0, False, ''),
332
                             old_e[1][1]])
333
        expected['h/e'] = (('h', 'e', 'e-id'), [old_e[1][0],
334
                                                ('r', 'b/d/e', 0, False, '')])
335
336
        state.unlock()
337
        try:
338
            new_state = dirstate.DirState.from_tree(tree, 'dirstate')
339
            try:
340
                new_state.save()
341
            finally:
342
                new_state.unlock()
343
        finally:
344
            state.lock_read()
345
        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.
346
347
class TestTreeToDirState(TestCaseWithDirState):
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
348
349
    def test_empty_to_dirstate(self):
350
        """We should be able to create a dirstate for an empty tree."""
351
        # There are no files on disk and no parents
352
        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.
353
        expected_result = ([], [
354
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
355
             [('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.
356
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
357
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
358
        state._validate()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
359
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
360
361
    def test_1_parents_empty_to_dirstate(self):
362
        # create a parent by doing a commit
363
        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.
364
        rev_id = tree.commit('first post').encode('utf8')
365
        root_stat_pack = dirstate.pack_stat(os.stat(tree.basedir))
366
        expected_result = ([rev_id], [
367
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
368
             [('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
369
              ('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.
370
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
371
        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.
372
        self.check_state_with_reopen(expected_result, state)
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
373
        state.lock_read()
374
        try:
375
            state._validate()
376
        finally:
377
            state.unlock()
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
378
379
    def test_2_parents_empty_to_dirstate(self):
380
        # create a parent by doing a commit
381
        tree = self.make_branch_and_tree('tree')
382
        rev_id = tree.commit('first post')
383
        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.
384
        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.
385
        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.
386
        expected_result = ([rev_id, rev_id2], [
387
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
388
             [('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
389
              ('d', '', 0, False, rev_id), # first parent details
390
              ('d', '', 0, False, rev_id2), # 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.
391
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
392
        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.
393
        self.check_state_with_reopen(expected_result, state)
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
394
        state.lock_read()
395
        try:
396
            state._validate()
397
        finally:
398
            state.unlock()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
399
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
400
    def test_empty_unknowns_are_ignored_to_dirstate(self):
401
        """We should be able to create a dirstate for an empty tree."""
402
        # There are no files on disk and no parents
403
        tree = self.make_branch_and_tree('tree')
1852.13.10 by Robert Collins
Use just the tree api to generate dirstate information.
404
        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.
405
        expected_result = ([], [
406
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
407
             [('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.
408
             ])])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
409
        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.
410
        self.check_state_with_reopen(expected_result, state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
411
1852.13.12 by Robert Collins
get actual parent info for the first parent.
412
    def get_tree_with_a_file(self):
413
        tree = self.make_branch_and_tree('tree')
414
        self.build_tree(['tree/a file'])
415
        tree.add('a file', 'a file id')
416
        return tree
417
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
418
    def test_non_empty_no_parents_to_dirstate(self):
419
        """We should be able to create a dirstate for an empty tree."""
1852.13.11 by Robert Collins
Get one content containing test passing.
420
        # There are files on disk and no parents
1852.13.12 by Robert Collins
get actual parent info for the first parent.
421
        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.
422
        expected_result = ([], [
423
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
424
             [('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.
425
             ]),
426
            (('', 'a file', 'a file id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
427
             [('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.
428
             ]),
429
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
430
        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.
431
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
432
433
    def test_1_parents_not_empty_to_dirstate(self):
434
        # create a parent by doing a commit
1852.13.12 by Robert Collins
get actual parent info for the first parent.
435
        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.
436
        rev_id = tree.commit('first post').encode('utf8')
1852.13.12 by Robert Collins
get actual parent info for the first parent.
437
        # change the current content to be different this will alter stat, sha
438
        # and length:
439
        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.
440
        expected_result = ([rev_id], [
441
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
442
             [('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
443
              ('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.
444
             ]),
445
            (('', 'a file', 'a file id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
446
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
447
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
448
               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.
449
             ]),
450
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
451
        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.
452
        self.check_state_with_reopen(expected_result, state)
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
453
454
    def test_2_parents_not_empty_to_dirstate(self):
455
        # create a parent by doing a commit
1852.13.13 by Robert Collins
2-parent case working.
456
        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.
457
        rev_id = tree.commit('first post').encode('utf8')
1852.13.6 by Robert Collins
start hooking in the prototype dirstate serialiser.
458
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
1852.13.13 by Robert Collins
2-parent case working.
459
        # change the current content to be different this will alter stat, sha
460
        # and length:
461
        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.
462
        rev_id2 = tree2.commit('second post').encode('utf8')
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
463
        tree.merge_from_branch(tree2.branch)
1852.13.13 by Robert Collins
2-parent case working.
464
        # change the current content to be different this will alter stat, sha
465
        # and length again, giving us three distinct values:
466
        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.
467
        expected_result = ([rev_id, rev_id2], [
468
            (('', '', tree.path2id('')), # common details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
469
             [('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
470
              ('d', '', 0, False, rev_id), # first parent details
471
              ('d', '', 0, False, rev_id2), # 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.
472
             ]),
473
            (('', 'a file', 'a file id'), # common
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
474
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
475
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
476
               rev_id), # first parent
477
              ('f', '314d796174c9412647c3ce07dfb5d36a94e72958', 14, False,
478
               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.
479
             ]),
480
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
481
        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.
482
        self.check_state_with_reopen(expected_result, state)
483
2255.7.94 by Martin Pool
Fix dirstate sorting bug and refine the _validate() assertions:
484
    def test_colliding_fileids(self):
485
        # test insertion of parents creating several entries at the same path.
486
        # we used to have a bug where they could cause the dirstate to break
487
        # its ordering invariants.
488
        # create some trees to test from
489
        parents = []
490
        for i in range(7):
491
            tree = self.make_branch_and_tree('tree%d' % i)
492
            self.build_tree(['tree%d/name' % i,])
493
            tree.add(['name'], ['file-id%d' % i])
494
            revision_id = 'revid-%d' % i
495
            tree.commit('message', rev_id=revision_id)
496
            parents.append((revision_id,
497
                tree.branch.repository.revision_tree(revision_id)))
498
        # now fold these trees into a dirstate
499
        state = dirstate.DirState.initialize('dirstate')
500
        try:
501
            state.set_parent_trees(parents, [])
502
            state._validate()
503
        finally:
504
            state.unlock()
505
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
506
507
class TestDirStateOnFile(TestCaseWithDirState):
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
508
509
    def test_construct_with_path(self):
510
        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.
511
        state = dirstate.DirState.from_tree(tree, 'dirstate.from_tree')
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
512
        # we want to be able to get the lines of the dirstate that we will
513
        # write to disk.
514
        lines = state.get_lines()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
515
        state.unlock()
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
516
        self.build_tree_contents([('dirstate', ''.join(lines))])
517
        # 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.
518
        # no parents, default tree content
519
        expected_result = ([], [
520
            (('', '', tree.path2id('')), # common details
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
521
             # current tree details, but new from_tree skips statting, it
522
             # uses set_state_from_inventory, and thus depends on the
523
             # inventory state.
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
524
             [('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.
525
             ])
526
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
527
        state = dirstate.DirState.on_file('dirstate')
528
        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.
529
        self.check_state_with_reopen(expected_result, state)
530
531
    def test_can_save_clean_on_file(self):
532
        tree = self.make_branch_and_tree('tree')
533
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
534
        try:
535
            # doing a save should work here as there have been no changes.
536
            state.save()
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
537
            # TODO: stat it and check it hasn't changed; may require waiting
538
            # for the state accuracy window.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
539
        finally:
540
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
541
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
542
    def test_can_save_in_read_lock(self):
543
        self.build_tree(['a-file'])
544
        state = dirstate.DirState.initialize('dirstate')
545
        try:
546
            # No stat and no sha1 sum.
547
            state.add('a-file', 'a-file-id', 'file', None, '')
548
            state.save()
549
        finally:
550
            state.unlock()
551
552
        # Now open in readonly mode
553
        state = dirstate.DirState.on_file('dirstate')
554
        state.lock_read()
555
        try:
556
            entry = state._get_entry(0, path_utf8='a-file')
557
            # The current sha1 sum should be empty
558
            self.assertEqual('', entry[1][0][1])
559
            # We should have a real entry.
560
            self.assertNotEqual((None, None), entry)
561
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
562
            # We should have gotten a real sha1
563
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
564
                             sha1sum)
565
566
            # The dirblock has been updated
567
            self.assertEqual(sha1sum, entry[1][0][1])
568
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
569
                             state._dirblock_state)
570
571
            del entry
572
            # Now, since we are the only one holding a lock, we should be able
573
            # to save and have it written to disk
574
            state.save()
575
        finally:
576
            state.unlock()
577
578
        # Re-open the file, and ensure that the state has been updated.
579
        state = dirstate.DirState.on_file('dirstate')
580
        state.lock_read()
581
        try:
582
            entry = state._get_entry(0, path_utf8='a-file')
583
            self.assertEqual(sha1sum, entry[1][0][1])
584
        finally:
585
            state.unlock()
586
587
    def test_save_fails_quietly_if_locked(self):
588
        """If dirstate is locked, save will fail without complaining."""
589
        self.build_tree(['a-file'])
590
        state = dirstate.DirState.initialize('dirstate')
591
        try:
592
            # No stat and no sha1 sum.
593
            state.add('a-file', 'a-file-id', 'file', None, '')
594
            state.save()
595
        finally:
596
            state.unlock()
597
598
        state = dirstate.DirState.on_file('dirstate')
599
        state.lock_read()
600
        try:
601
            entry = state._get_entry(0, path_utf8='a-file')
602
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
603
            # We should have gotten a real sha1
604
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
605
                             sha1sum)
606
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
607
                             state._dirblock_state)
608
609
            # Now, before we try to save, grab another dirstate, and take out a
610
            # read lock.
611
            # TODO: jam 20070315 Ideally this would be locked by another
612
            #       process. To make sure the file is really OS locked.
613
            state2 = dirstate.DirState.on_file('dirstate')
614
            state2.lock_read()
615
            try:
616
                # This won't actually write anything, because it couldn't grab
617
                # a write lock. But it shouldn't raise an error, either.
618
                # TODO: jam 20070315 We should probably distinguish between
619
                #       being dirty because of 'update_entry'. And dirty
620
                #       because of real modification. So that save() *does*
621
                #       raise a real error if it fails when we have real
622
                #       modifications.
623
                state.save()
624
            finally:
625
                state2.unlock()
626
        finally:
627
            state.unlock()
628
        
629
        # The file on disk should not be modified.
630
        state = dirstate.DirState.on_file('dirstate')
631
        state.lock_read()
632
        try:
633
            entry = state._get_entry(0, path_utf8='a-file')
634
            self.assertEqual('', entry[1][0][1])
635
        finally:
636
            state.unlock()
637
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
638
639
class TestDirStateInitialize(TestCaseWithDirState):
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
640
641
    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.
642
        expected_result = ([], [
643
            (('', '', 'TREE_ROOT'), # common details
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
644
             [('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.
645
             ])
646
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
647
        state = dirstate.DirState.initialize('dirstate')
648
        try:
649
            self.assertIsInstance(state, dirstate.DirState)
650
            lines = state.get_lines()
651
            self.assertFileEqual(''.join(state.get_lines()),
652
                'dirstate')
653
            self.check_state_with_reopen(expected_result, state)
654
        except:
655
            state.unlock()
656
            raise
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
657
658
659
class TestDirStateManipulations(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
660
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.
661
    def test_set_state_from_inventory_no_content_no_parents(self):
662
        # setting the current inventory is a slow but important api to support.
663
        tree1 = self.make_branch_and_memory_tree('tree1')
664
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
665
        try:
666
            tree1.add('')
667
            revid1 = tree1.commit('foo').encode('utf8')
668
            root_id = tree1.inventory.root.file_id
669
            inv = tree1.inventory
670
        finally:
671
            tree1.unlock()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
672
        expected_result = [], [
673
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
674
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
675
        state = dirstate.DirState.initialize('dirstate')
676
        try:
677
            state.set_state_from_inventory(inv)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
678
            self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
679
                             state._header_state)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
680
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
681
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
682
        except:
683
            state.unlock()
684
            raise
685
        else:
686
            # This will unlock it
687
            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.
688
2255.2.4 by Robert Collins
Snapshot dirstate development
689
    def test_set_path_id_no_parents(self):
690
        """The id of a path can be changed trivally with no parents."""
691
        state = dirstate.DirState.initialize('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
692
        try:
693
            # check precondition to be sure the state does change appropriately.
694
            self.assertEqual(
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
695
                [(('', '', 'TREE_ROOT'), [('d', '', 0, False,
696
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])],
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
697
                list(state._iter_entries()))
698
            state.set_path_id('', 'foobarbaz')
699
            expected_rows = [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
700
                (('', '', 'foobarbaz'), [('d', '', 0, False,
701
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
702
            self.assertEqual(expected_rows, list(state._iter_entries()))
703
            # should work across save too
704
            state.save()
705
        finally:
706
            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.
707
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
708
        state.lock_read()
709
        try:
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
710
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
711
            self.assertEqual(expected_rows, list(state._iter_entries()))
712
        finally:
713
            state.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
714
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
715
    def test_set_path_id_with_parents(self):
716
        """Set the root file id in a dirstate with parents"""
717
        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
718
        # in case the default tree format uses a different root id
719
        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
720
        mt.commit('foo', rev_id='parent-revid')
721
        rt = mt.branch.repository.revision_tree('parent-revid')
722
        state = dirstate.DirState.initialize('dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
723
        state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
724
        try:
725
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
726
            state.set_path_id('', 'foobarbaz')
2255.2.177 by Martin Pool
merge dirstate sorting fix, add more validation tests
727
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
728
            # now see that it is what we expected
729
            expected_rows = [
730
                (('', '', 'TREE_ROOT'),
731
                    [('a', '', 0, False, ''),
732
                     ('d', '', 0, False, 'parent-revid'),
733
                     ]),
734
                (('', '', 'foobarbaz'),
735
                    [('d', '', 0, False, ''),
736
                     ('a', '', 0, False, ''),
737
                     ]),
738
                ]
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
739
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
740
            self.assertEqual(expected_rows, list(state._iter_entries()))
741
            # should work across save too
742
            state.save()
743
        finally:
744
            state.unlock()
745
        # now flush & check we get the same
746
        state = dirstate.DirState.on_file('dirstate')
747
        state.lock_read()
748
        try:
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
749
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
750
            self.assertEqual(expected_rows, list(state._iter_entries()))
751
        finally:
752
            state.unlock()
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
753
        # now change within an existing file-backed state
754
        state.lock_write()
755
        try:
756
            state._validate()
757
            state.set_path_id('', 'tree-root-2')
758
            state._validate()
759
        finally:
760
            state.unlock()
761
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
762
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.
763
    def test_set_parent_trees_no_content(self):
764
        # set_parent_trees is a slow but important api to support.
765
        tree1 = self.make_branch_and_memory_tree('tree1')
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
766
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
767
        try:
768
            tree1.add('')
769
            revid1 = tree1.commit('foo')
770
        finally:
771
            tree1.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
772
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
773
        tree2 = MemoryTree.create_on_branch(branch2)
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
774
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
775
        try:
776
            revid2 = tree2.commit('foo')
777
            root_id = tree2.inventory.root.file_id
778
        finally:
779
            tree2.unlock()
780
        state = dirstate.DirState.initialize('dirstate')
781
        try:
782
            state.set_path_id('', root_id)
783
            state.set_parent_trees(
784
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
785
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
786
                 ('ghost-rev', None)),
787
                ['ghost-rev'])
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
788
            # check we can reopen and use the dirstate after setting parent
789
            # trees.
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
790
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
791
            state.save()
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
792
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
793
        finally:
794
            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.
795
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
796
        state.lock_write()
797
        try:
798
            self.assertEqual([revid1, revid2, 'ghost-rev'],
799
                             state.get_parent_ids())
800
            # iterating the entire state ensures that the state is parsable.
801
            list(state._iter_entries())
802
            # be sure that it sets not appends - change it
803
            state.set_parent_trees(
804
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
805
                 ('ghost-rev', None)),
806
                ['ghost-rev'])
807
            # and now put it back.
808
            state.set_parent_trees(
809
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
810
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
811
                 ('ghost-rev', tree2.branch.repository.revision_tree(None))),
812
                ['ghost-rev'])
813
            self.assertEqual([revid1, revid2, 'ghost-rev'],
814
                             state.get_parent_ids())
815
            # the ghost should be recorded as such by set_parent_trees.
816
            self.assertEqual(['ghost-rev'], state.get_ghosts())
817
            self.assertEqual(
818
                [(('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
819
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
820
                  ('d', '', 0, False, revid1),
821
                  ('d', '', 0, False, revid2)
822
                  ])],
823
                list(state._iter_entries()))
824
        finally:
825
            state.unlock()
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
826
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
827
    def test_set_parent_trees_file_missing_from_tree(self):
828
        # 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
829
        # 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
830
        # separate trees.
831
        # set_parent_trees is a slow but important api to support.
832
        tree1 = self.make_branch_and_memory_tree('tree1')
833
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
834
        try:
835
            tree1.add('')
836
            tree1.add(['a file'], ['file-id'], ['file'])
837
            tree1.put_file_bytes_non_atomic('file-id', 'file-content')
838
            revid1 = tree1.commit('foo')
839
        finally:
840
            tree1.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
841
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
842
        tree2 = MemoryTree.create_on_branch(branch2)
843
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
844
        try:
845
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
846
            revid2 = tree2.commit('foo')
847
            root_id = tree2.inventory.root.file_id
848
        finally:
849
            tree2.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
850
        # check the layout in memory
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
851
        expected_result = [revid1.encode('utf8'), revid2.encode('utf8')], [
852
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
853
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
854
             ('d', '', 0, False, revid1.encode('utf8')),
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
855
             ('d', '', 0, False, revid2.encode('utf8'))
856
             ]),
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
857
            (('', 'a file', 'file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
858
             ('a', '', 0, False, ''),
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
859
             ('f', '2439573625385400f2a669657a7db6ae7515d371', 12, False,
860
              revid1.encode('utf8')),
861
             ('f', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False,
862
              revid2.encode('utf8'))
863
             ])
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
864
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
865
        state = dirstate.DirState.initialize('dirstate')
866
        try:
867
            state.set_path_id('', root_id)
868
            state.set_parent_trees(
869
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
870
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
871
                 ), [])
872
        except:
873
            state.unlock()
874
            raise
875
        else:
876
            # check_state_with_reopen will unlock
877
            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
878
1852.13.20 by Robert Collins
Steps toward an object model.
879
    ### add a path via _set_data - so we dont need delta work, just
880
    # 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.
881
1852.13.25 by Robert Collins
Snapshot state
882
    def test_add_path_to_root_no_parents_all_data(self):
883
        # The most trivial addition of a path is when there are no parents and
884
        # its in the root and all data about the file is supplied
885
        self.build_tree(['a file'])
886
        stat = os.lstat('a file')
887
        # the 1*20 is the sha1 pretend value.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
888
        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.
889
        expected_entries = [
890
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
891
             ('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.
892
             ]),
893
            (('', 'a file', 'a file id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
894
             ('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.
895
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
896
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
897
        try:
898
            state.add('a file', 'a file id', 'file', stat, '1'*20)
899
            # having added it, it should be in the output of iter_entries.
900
            self.assertEqual(expected_entries, list(state._iter_entries()))
901
            # saving and reloading should not affect this.
902
            state.save()
903
        finally:
904
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
905
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
906
        state.lock_read()
907
        try:
908
            self.assertEqual(expected_entries, list(state._iter_entries()))
909
        finally:
910
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
911
912
    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.
913
        """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.
914
915
        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.
916
        once dirstate is stable and if it is merged with WorkingTree3, consider
917
        removing this copy of the test.
918
        """
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
919
        self.build_tree(['unversioned/', 'unversioned/a file'])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
920
        state = dirstate.DirState.initialize('dirstate')
921
        try:
922
            self.assertRaises(errors.NotVersionedError, state.add,
923
                'unversioned/a file', 'a file id', 'file', None, None)
924
        finally:
925
            state.unlock()
926
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
927
    def test_add_directory_to_root_no_parents_all_data(self):
928
        # The most trivial addition of a dir is when there are no parents and
929
        # its in the root and all data about the file is supplied
930
        self.build_tree(['a dir/'])
931
        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.
932
        expected_entries = [
933
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
934
             ('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.
935
             ]),
936
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
937
             ('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.
938
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
939
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
940
        state = dirstate.DirState.initialize('dirstate')
941
        try:
942
            state.add('a dir', 'a dir id', 'directory', stat, None)
943
            # having added it, it should be in the output of iter_entries.
944
            self.assertEqual(expected_entries, list(state._iter_entries()))
945
            # saving and reloading should not affect this.
946
            state.save()
947
        finally:
948
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
949
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
950
        state.lock_read()
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
951
        state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
952
        try:
953
            self.assertEqual(expected_entries, list(state._iter_entries()))
954
        finally:
955
            state.unlock()
1852.13.25 by Robert Collins
Snapshot state
956
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.
957
    def test_add_symlink_to_root_no_parents_all_data(self):
958
        # The most trivial addition of a symlink when there are no parents and
959
        # its in the root and all data about the file is supplied
2321.3.8 by Alexander Belchenko
Cleanup patch after John's review
960
        # bzr doesn't support fake symlinks on windows, yet.
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
961
        if not has_symlinks():
962
            raise TestSkipped("No symlink support")
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.
963
        os.symlink('target', 'a link')
964
        stat = os.lstat('a link')
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
965
        expected_entries = [
966
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
967
             ('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.
968
             ]),
969
            (('', 'a link', 'a link id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
970
             ('l', 'target', 6, 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.
971
             ]),
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.
972
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
973
        state = dirstate.DirState.initialize('dirstate')
974
        try:
975
            state.add('a link', 'a link id', 'symlink', stat, 'target')
976
            # having added it, it should be in the output of iter_entries.
977
            self.assertEqual(expected_entries, list(state._iter_entries()))
978
            # saving and reloading should not affect this.
979
            state.save()
980
        finally:
981
            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.
982
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
983
        state.lock_read()
984
        try:
985
            self.assertEqual(expected_entries, list(state._iter_entries()))
986
        finally:
987
            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.
988
989
    def test_add_directory_and_child_no_parents_all_data(self):
990
        # after adding a directory, we should be able to add children to it.
991
        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.
992
        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.
993
        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.
994
        expected_entries = [
995
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
996
             ('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.
997
             ]),
998
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
999
             ('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.
1000
             ]),
1001
            (('a dir', 'a file', 'a file id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1002
             ('f', '1'*20, 25, False,
1003
              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.
1004
             ]),
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.
1005
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1006
        state = dirstate.DirState.initialize('dirstate')
1007
        try:
1008
            state.add('a dir', 'a dir id', 'directory', dirstat, None)
1009
            state.add('a dir/a file', 'a file id', 'file', filestat, '1'*20)
1010
            # added it, it should be in the output of iter_entries.
1011
            self.assertEqual(expected_entries, list(state._iter_entries()))
1012
            # saving and reloading should not affect this.
1013
            state.save()
1014
        finally:
1015
            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.
1016
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1017
        state.lock_read()
1018
        try:
1019
            self.assertEqual(expected_entries, list(state._iter_entries()))
1020
        finally:
1021
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1022
2255.7.93 by Martin Pool
Add support for tree-references in dirstate
1023
    def test_add_tree_reference(self):
1024
        # make a dirstate and add a tree reference
1025
        state = dirstate.DirState.initialize('dirstate')
1026
        expected_entry = (
1027
            ('', 'subdir', 'subdir-id'),
1028
            [('t', 'subtree-123123', 0, False,
1029
              'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')],
1030
            )
1031
        try:
1032
            state.add('subdir', 'subdir-id', 'tree-reference', None, 'subtree-123123')
1033
            entry = state._get_entry(0, 'subdir-id', 'subdir')
1034
            self.assertEqual(entry, expected_entry)
1035
            state._validate()
1036
            state.save()
1037
        finally:
1038
            state.unlock()
1039
        # now check we can read it back
1040
        state.lock_read()
1041
        state._validate()
1042
        try:
1043
            entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1044
            self.assertEqual(entry, entry2)
1045
            self.assertEqual(entry, expected_entry)
1046
            # and lookup by id should work too
1047
            entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1048
            self.assertEqual(entry, expected_entry)
1049
        finally:
1050
            state.unlock()
1051
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1052
    def test_add_forbidden_names(self):
1053
        state = dirstate.DirState.initialize('dirstate')
2255.2.233 by John Arbash Meinel
DirState.initialize returns a locked state, unlock as part of cleanup.
1054
        self.addCleanup(state.unlock)
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1055
        self.assertRaises(errors.BzrError,
1056
            state.add, '.', 'ass-id', 'directory', None, None)
1057
        self.assertRaises(errors.BzrError,
1058
            state.add, '..', 'ass-id', 'directory', None, None)
1059
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1060
1061
class TestGetLines(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
1062
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.
1063
    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.
1064
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1065
        try:
2255.7.20 by John Arbash Meinel
update test for format 3, and enable caching of path split while lock is held.
1066
            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.
1067
                'crc32: 41262208\n',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1068
                'num_entries: 2\n',
1069
                '0\x00\n\x00'
1070
                '0\x00\n\x00'
1071
                '\x00\x00a-root-value\x00'
1072
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1073
                '\x00subdir\x00subdir-id\x00'
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1074
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1075
                ], state.get_lines())
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1076
        finally:
1077
            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.
1078
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1079
    def test_entry_to_line(self):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1080
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1081
        try:
1082
            self.assertEqual(
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1083
                '\x00\x00a-root-value\x00d\x00\x000\x00n'
1084
                '\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1085
                state._entry_to_line(state._dirblocks[0][1][0]))
1086
        finally:
1087
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1088
1089
    def test_entry_to_line_with_parent(self):
1090
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1091
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1092
            ('d', '', 0, False, packed_stat), # current tree details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1093
             # first: a pointer to the current location
1094
            ('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.
1095
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1096
        state = dirstate.DirState.initialize('dirstate')
1097
        try:
1098
            self.assertEqual(
1099
                '\x00\x00a-root-value\x00'
1100
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1101
                'a\x00dirname/basename\x000\x00n\x00',
1102
                state._entry_to_line(root_entry))
1103
        finally:
1104
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1105
1106
    def test_entry_to_line_with_two_parents_at_different_paths(self):
1107
        # / in the tree, at / in one parent and /dirname/basename in the other.
1108
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1109
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1110
            ('d', '', 0, False, packed_stat), # current tree details
1111
            ('d', '', 0, False, 'rev_id'), # first parent details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1112
             # second: a pointer to the current location
1113
            ('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.
1114
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1115
        state = dirstate.DirState.initialize('dirstate')
1116
        try:
1117
            self.assertEqual(
1118
                '\x00\x00a-root-value\x00'
1119
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1120
                'd\x00\x000\x00n\x00rev_id\x00'
1121
                'a\x00dirname/basename\x000\x00n\x00',
1122
                state._entry_to_line(root_entry))
1123
        finally:
1124
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1125
1126
    def test_iter_entries(self):
1127
        # 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.
1128
        # this is for get_lines to be easy to read.
1129
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1130
        dirblocks = []
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1131
        root_entries = [(('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1132
            ('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.
1133
            ])]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1134
        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.
1135
        # 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.
1136
        subdir_entry = ('', 'subdir', 'subdir-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1137
            ('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.
1138
            ]
1139
        afile_entry = ('', 'afile', 'afile-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1140
            ('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.
1141
            ]
1142
        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.
1143
        # 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.
1144
        file_entry2 = ('subdir', '2file', '2file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1145
            ('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.
1146
            ]
1147
        dirblocks.append(('subdir', [file_entry2]))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1148
        state = dirstate.DirState.initialize('dirstate')
1149
        try:
1150
            state._set_data([], dirblocks)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1151
            expected_entries = [root_entries[0], subdir_entry, afile_entry,
1152
                                file_entry2]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1153
            self.assertEqual(expected_entries, list(state._iter_entries()))
1154
        finally:
1155
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1156
1157
1158
class TestGetBlockRowIndex(TestCaseWithDirState):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1159
1160
    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.
1161
        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.
1162
        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.
1163
            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.
1164
        if dir_present:
1165
            block = state._dirblocks[block_index]
1166
            self.assertEqual(dirname, block[0])
1167
        if dir_present and file_present:
1168
            row = state._dirblocks[block_index][1][row_index]
1169
            self.assertEqual(dirname, row[0][0])
1170
            self.assertEqual(basename, row[0][1])
1171
1172
    def test_simple_structure(self):
1173
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1174
        self.addCleanup(state.unlock)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1175
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
1176
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
1177
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
1178
        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
1179
        self.assertBlockRowIndexEqual(2, 0, False, False, state,
1180
                                      'subdir', 'foo', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1181
1182
    def test_complex_structure_exists(self):
1183
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1184
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1185
        # Make sure we can find everything that exists
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1186
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1187
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
1188
        self.assertBlockRowIndexEqual(1, 1, True, True, state, '', 'b', 0)
1189
        self.assertBlockRowIndexEqual(1, 2, True, True, state, '', 'c', 0)
1190
        self.assertBlockRowIndexEqual(1, 3, True, True, state, '', 'd', 0)
1191
        self.assertBlockRowIndexEqual(2, 0, True, True, state, 'a', 'e', 0)
1192
        self.assertBlockRowIndexEqual(2, 1, True, True, state, 'a', 'f', 0)
1193
        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
1194
        self.assertBlockRowIndexEqual(3, 1, True, True, state,
1195
                                      'b', 'h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1196
1197
    def test_complex_structure_missing(self):
1198
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1199
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1200
        # Make sure things would be inserted in the right locations
1201
        # '_' comes before 'a'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1202
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1203
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', '_', 0)
1204
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'aa', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1205
        self.assertBlockRowIndexEqual(1, 4, True, False, state,
1206
                                      '', 'h\xc3\xa5', 0)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1207
        self.assertBlockRowIndexEqual(2, 0, False, False, state, '_', 'a', 0)
1208
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'aa', 'a', 0)
1209
        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.
1210
        # This would be inserted between a/ and b/
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1211
        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.
1212
        # Put at the end
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1213
        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.
1214
1215
1216
class TestGetEntry(TestCaseWithDirState):
1217
1218
    def assertEntryEqual(self, dirname, basename, file_id, state, path, index):
1219
        """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.
1220
        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.
1221
        if file_id is None:
1222
            self.assertEqual((None, None), entry)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1223
        else:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1224
            cur = entry[0]
1225
            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.
1226
1227
    def test_simple_structure(self):
1228
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1229
        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.
1230
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1231
        self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
1232
        self.assertEntryEqual(None, None, None, state, 'missing', 0)
1233
        self.assertEntryEqual(None, None, None, state, 'missing/foo', 0)
1234
        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.
1235
1236
    def test_complex_structure_exists(self):
1237
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1238
        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.
1239
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1240
        self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
1241
        self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
1242
        self.assertEntryEqual('', 'c', 'c-file', state, 'c', 0)
1243
        self.assertEntryEqual('', 'd', 'd-file', state, 'd', 0)
1244
        self.assertEntryEqual('a', 'e', 'e-dir', state, 'a/e', 0)
1245
        self.assertEntryEqual('a', 'f', 'f-file', state, 'a/f', 0)
1246
        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
1247
        self.assertEntryEqual('b', 'h\xc3\xa5', 'h-\xc3\xa5-file', state,
1248
                              'b/h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1249
1250
    def test_complex_structure_missing(self):
1251
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1252
        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.
1253
        self.assertEntryEqual(None, None, None, state, '_', 0)
1254
        self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
1255
        self.assertEntryEqual(None, None, None, state, 'a/b', 0)
1256
        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.
1257
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1258
    def test_get_entry_uninitialized(self):
1259
        """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.
1260
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1261
        try:
1262
            state.save()
1263
        finally:
1264
            state.unlock()
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1265
        del state
1266
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1267
        state.lock_read()
1268
        try:
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1269
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1270
                             state._header_state)
1271
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1272
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1273
            self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1274
        finally:
1275
            state.unlock()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1276
1277
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1278
class TestDirstateSortOrder(TestCaseWithTransport):
1279
    """Test that DirState adds entries in the right order."""
1280
1281
    def test_add_sorting(self):
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1282
        """Add entries in lexicographical order, we get path sorted order.
1283
1284
        This tests it to a depth of 4, to make sure we don't just get it right
1285
        at a single depth. 'a/a' should come before 'a-a', even though it
1286
        doesn't lexicographically.
1287
        """
1288
        dirs = ['a', 'a/a', 'a/a/a', 'a/a/a/a',
1289
                '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.
1290
               ]
1291
        null_sha = ''
1292
        state = dirstate.DirState.initialize('dirstate')
1293
        self.addCleanup(state.unlock)
1294
1295
        fake_stat = os.stat('dirstate')
1296
        for d in dirs:
1297
            d_id = d.replace('/', '_')+'-id'
1298
            file_path = d + '/f'
1299
            file_id = file_path.replace('/', '_')+'-id'
1300
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1301
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1302
1303
        expected = ['', '', 'a',
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1304
                'a/a', 'a/a/a', 'a/a/a/a',
1305
                '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.
1306
               ]
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1307
        split = lambda p:p.split('/')
1308
        self.assertEqual(sorted(expected, key=split), expected)
1309
        dirblock_names = [d[0] for d in state._dirblocks]
1310
        self.assertEqual(expected, dirblock_names)
1311
1312
    def test_set_parent_trees_correct_order(self):
1313
        """After calling set_parent_trees() we should maintain the order."""
1314
        dirs = ['a', 'a-a', 'a/a']
1315
        null_sha = ''
1316
        state = dirstate.DirState.initialize('dirstate')
1317
        self.addCleanup(state.unlock)
1318
1319
        fake_stat = os.stat('dirstate')
1320
        for d in dirs:
1321
            d_id = d.replace('/', '_')+'-id'
1322
            file_path = d + '/f'
1323
            file_id = file_path.replace('/', '_')+'-id'
1324
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1325
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1326
1327
        expected = ['', '', 'a', 'a/a', 'a-a']
1328
        dirblock_names = [d[0] for d in state._dirblocks]
1329
        self.assertEqual(expected, dirblock_names)
1330
1331
        # *really* cheesy way to just get an empty tree
1332
        repo = self.make_repository('repo')
1333
        empty_tree = repo.revision_tree(None)
1334
        state.set_parent_trees([('null:', empty_tree)], [])
1335
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1336
        dirblock_names = [d[0] for d in state._dirblocks]
1337
        self.assertEqual(expected, dirblock_names)
1338
1339
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1340
class InstrumentedDirState(dirstate.DirState):
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1341
    """An DirState with instrumented sha1 functionality."""
1342
1343
    def __init__(self, path):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1344
        super(InstrumentedDirState, self).__init__(path)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1345
        self._time_offset = 0
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1346
        self._log = []
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1347
1348
    def _sha_cutoff_time(self):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1349
        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.
1350
        self._cutoff_time = timestamp + self._time_offset
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1351
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1352
    def _sha1_file(self, abspath, entry):
1353
        self._log.append(('sha1', abspath))
1354
        return super(InstrumentedDirState, self)._sha1_file(abspath, entry)
1355
1356
    def _read_link(self, abspath, old_link):
1357
        self._log.append(('read_link', abspath, old_link))
1358
        return super(InstrumentedDirState, self)._read_link(abspath, old_link)
1359
1360
    def _lstat(self, abspath, entry):
1361
        self._log.append(('lstat', abspath))
1362
        return super(InstrumentedDirState, self)._lstat(abspath, entry)
1363
1364
    def _is_executable(self, mode, old_executable):
1365
        self._log.append(('is_exec', mode, old_executable))
1366
        return super(InstrumentedDirState, self)._is_executable(mode,
1367
                                                                old_executable)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1368
1369
    def adjust_time(self, secs):
1370
        """Move the clock forward or back.
1371
1372
        :param secs: The amount to adjust the clock by. Positive values make it
1373
        seem as if we are in the future, negative values make it seem like we
1374
        are in the past.
1375
        """
1376
        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.
1377
        self._cutoff_time = None
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1378
1379
1380
class _FakeStat(object):
1381
    """A class with the same attributes as a real stat result."""
1382
1383
    def __init__(self, size, mtime, ctime, dev, ino, mode):
1384
        self.st_size = size
1385
        self.st_mtime = mtime
1386
        self.st_ctime = ctime
1387
        self.st_dev = dev
1388
        self.st_ino = ino
1389
        self.st_mode = mode
1390
1391
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1392
class TestUpdateEntry(TestCaseWithDirState):
1393
    """Test the DirState.update_entry functions"""
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1394
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1395
    def get_state_with_a(self):
1396
        """Create a DirState tracking a single object named 'a'"""
1397
        state = InstrumentedDirState.initialize('dirstate')
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1398
        self.addCleanup(state.unlock)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1399
        state.add('a', 'a-id', 'file', None, '')
1400
        entry = state._get_entry(0, path_utf8='a')
1401
        return state, entry
1402
1403
    def test_update_entry(self):
1404
        state, entry = self.get_state_with_a()
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1405
        self.build_tree(['a'])
1406
        # Add one where we don't provide the stat or sha already
1407
        self.assertEqual(('', 'a', 'a-id'), entry[0])
1408
        self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1409
                         entry[1])
1410
        # Flush the buffers to disk
1411
        state.save()
1412
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1413
                         state._dirblock_state)
1414
1415
        stat_value = os.lstat('a')
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1416
        packed_stat = dirstate.pack_stat(stat_value)
1417
        link_or_sha1 = state.update_entry(entry, abspath='a',
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1418
                                          stat_value=stat_value)
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1419
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1420
                         link_or_sha1)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1421
1422
        # The dirblock entry should be updated with the new info
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1423
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1424
                         entry[1])
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1425
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1426
                         state._dirblock_state)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1427
        mode = stat_value.st_mode
1428
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1429
1430
        state.save()
1431
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1432
                         state._dirblock_state)
1433
1434
        # If we do it again right away, we don't know if the file has changed
1435
        # so we will re-read the file. Roll the clock back so the file is
1436
        # guaranteed to look too new.
1437
        state.adjust_time(-10)
1438
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1439
        link_or_sha1 = state.update_entry(entry, abspath='a',
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1440
                                          stat_value=stat_value)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1441
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1442
                          ('sha1', 'a'), ('is_exec', mode, False),
1443
                         ], state._log)
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1444
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1445
                         link_or_sha1)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1446
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1447
                         state._dirblock_state)
1448
        state.save()
1449
1450
        # However, if we move the clock forward so the file is considered
1451
        # "stable", it should just returned the cached value.
1452
        state.adjust_time(20)
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1453
        link_or_sha1 = state.update_entry(entry, abspath='a',
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1454
                                          stat_value=stat_value)
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1455
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1456
                         link_or_sha1)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1457
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1458
                          ('sha1', 'a'), ('is_exec', mode, False),
1459
                         ], state._log)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1460
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1461
    def test_update_entry_no_stat_value(self):
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1462
        """Passing the stat_value is optional."""
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1463
        state, entry = self.get_state_with_a()
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1464
        state.adjust_time(-10) # Make sure the file looks new
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1465
        self.build_tree(['a'])
1466
        # Add one where we don't provide the stat or sha already
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1467
        link_or_sha1 = state.update_entry(entry, abspath='a')
1468
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1469
                         link_or_sha1)
1470
        stat_value = os.lstat('a')
1471
        self.assertEqual([('lstat', 'a'), ('sha1', 'a'),
1472
                          ('is_exec', stat_value.st_mode, False),
1473
                         ], state._log)
1474
1475
    def test_update_entry_symlink(self):
1476
        """Update entry should read symlinks."""
1477
        if not osutils.has_symlinks():
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1478
            # PlatformDeficiency / TestSkipped
1479
            raise TestSkipped("No symlink support")
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1480
        state, entry = self.get_state_with_a()
1481
        state.save()
1482
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1483
                         state._dirblock_state)
1484
        os.symlink('target', 'a')
1485
1486
        state.adjust_time(-10) # Make the symlink look new
1487
        stat_value = os.lstat('a')
1488
        packed_stat = dirstate.pack_stat(stat_value)
1489
        link_or_sha1 = state.update_entry(entry, abspath='a',
1490
                                          stat_value=stat_value)
1491
        self.assertEqual('target', link_or_sha1)
1492
        self.assertEqual([('read_link', 'a', '')], state._log)
1493
        # Dirblock is updated
1494
        self.assertEqual([('l', link_or_sha1, 6, False, packed_stat)],
1495
                         entry[1])
1496
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1497
                         state._dirblock_state)
1498
1499
        # Because the stat_value looks new, we should re-read the target
1500
        link_or_sha1 = state.update_entry(entry, abspath='a',
1501
                                          stat_value=stat_value)
1502
        self.assertEqual('target', link_or_sha1)
1503
        self.assertEqual([('read_link', 'a', ''),
1504
                          ('read_link', 'a', 'target'),
1505
                         ], state._log)
1506
        state.adjust_time(+20) # Skip into the future, all files look old
1507
        link_or_sha1 = state.update_entry(entry, abspath='a',
1508
                                          stat_value=stat_value)
1509
        self.assertEqual('target', link_or_sha1)
1510
        # There should not be a new read_link call.
1511
        # (this is a weak assertion, because read_link is fairly inexpensive,
1512
        # versus the number of symlinks that we would have)
1513
        self.assertEqual([('read_link', 'a', ''),
1514
                          ('read_link', 'a', 'target'),
1515
                         ], state._log)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1516
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1517
    def test_update_entry_dir(self):
1518
        state, entry = self.get_state_with_a()
1519
        self.build_tree(['a/'])
1520
        self.assertIs(None, state.update_entry(entry, 'a'))
1521
1522
    def create_and_test_file(self, state, entry):
1523
        """Create a file at 'a' and verify the state finds it.
1524
1525
        The state should already be versioning *something* at 'a'. This makes
1526
        sure that state.update_entry recognizes it as a file.
1527
        """
1528
        self.build_tree(['a'])
1529
        stat_value = os.lstat('a')
1530
        packed_stat = dirstate.pack_stat(stat_value)
1531
1532
        link_or_sha1 = state.update_entry(entry, abspath='a')
1533
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1534
                         link_or_sha1)
1535
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1536
                         entry[1])
1537
        return packed_stat
1538
1539
    def create_and_test_dir(self, state, entry):
1540
        """Create a directory at 'a' and verify the state finds it.
1541
1542
        The state should already be versioning *something* at 'a'. This makes
1543
        sure that state.update_entry recognizes it as a directory.
1544
        """
1545
        self.build_tree(['a/'])
1546
        stat_value = os.lstat('a')
1547
        packed_stat = dirstate.pack_stat(stat_value)
1548
1549
        link_or_sha1 = state.update_entry(entry, abspath='a')
1550
        self.assertIs(None, link_or_sha1)
1551
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1552
1553
        return packed_stat
1554
1555
    def create_and_test_symlink(self, state, entry):
1556
        """Create a symlink at 'a' and verify the state finds it.
1557
1558
        The state should already be versioning *something* at 'a'. This makes
1559
        sure that state.update_entry recognizes it as a symlink.
1560
1561
        This should not be called if this platform does not have symlink
1562
        support.
1563
        """
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1564
        # caller should care about skipping test on platforms without symlinks
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1565
        os.symlink('path/to/foo', 'a')
1566
1567
        stat_value = os.lstat('a')
1568
        packed_stat = dirstate.pack_stat(stat_value)
1569
1570
        link_or_sha1 = state.update_entry(entry, abspath='a')
1571
        self.assertEqual('path/to/foo', link_or_sha1)
1572
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1573
                         entry[1])
1574
        return packed_stat
1575
1576
    def test_update_missing_file(self):
1577
        state, entry = self.get_state_with_a()
1578
        packed_stat = self.create_and_test_file(state, entry)
1579
        # Now if we delete the file, update_entry should recover and
1580
        # return None.
1581
        os.remove('a')
1582
        self.assertIs(None, state.update_entry(entry, abspath='a'))
1583
        # And the record shouldn't be changed.
1584
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1585
        self.assertEqual([('f', digest, 14, False, packed_stat)],
1586
                         entry[1])
1587
1588
    def test_update_missing_dir(self):
1589
        state, entry = self.get_state_with_a()
1590
        packed_stat = self.create_and_test_dir(state, entry)
1591
        # Now if we delete the directory, update_entry should recover and
1592
        # return None.
1593
        os.rmdir('a')
1594
        self.assertIs(None, state.update_entry(entry, abspath='a'))
1595
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1596
1597
    def test_update_missing_symlink(self):
1598
        if not osutils.has_symlinks():
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1599
            # PlatformDeficiency / TestSkipped
1600
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1601
        state, entry = self.get_state_with_a()
1602
        packed_stat = self.create_and_test_symlink(state, entry)
1603
        os.remove('a')
1604
        self.assertIs(None, state.update_entry(entry, abspath='a'))
1605
        # And the record shouldn't be changed.
1606
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1607
                         entry[1])
1608
1609
    def test_update_file_to_dir(self):
1610
        """If a file changes to a directory we return None for the sha.
1611
        We also update the inventory record.
1612
        """
1613
        state, entry = self.get_state_with_a()
1614
        self.create_and_test_file(state, entry)
1615
        os.remove('a')
1616
        self.create_and_test_dir(state, entry)
1617
1618
    def test_update_file_to_symlink(self):
1619
        """File becomes a symlink"""
1620
        if not osutils.has_symlinks():
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1621
            # PlatformDeficiency / TestSkipped
1622
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1623
        state, entry = self.get_state_with_a()
1624
        self.create_and_test_file(state, entry)
1625
        os.remove('a')
1626
        self.create_and_test_symlink(state, entry)
1627
1628
    def test_update_dir_to_file(self):
1629
        """Directory becoming a file updates the entry."""
1630
        state, entry = self.get_state_with_a()
1631
        self.create_and_test_dir(state, entry)
1632
        os.rmdir('a')
1633
        self.create_and_test_file(state, entry)
1634
1635
    def test_update_dir_to_symlink(self):
1636
        """Directory becomes a symlink"""
1637
        if not osutils.has_symlinks():
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1638
            # PlatformDeficiency / TestSkipped
1639
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1640
        state, entry = self.get_state_with_a()
1641
        self.create_and_test_dir(state, entry)
1642
        os.rmdir('a')
1643
        self.create_and_test_symlink(state, entry)
1644
1645
    def test_update_symlink_to_file(self):
1646
        """Symlink becomes a file"""
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1647
        if not has_symlinks():
1648
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1649
        state, entry = self.get_state_with_a()
1650
        self.create_and_test_symlink(state, entry)
1651
        os.remove('a')
1652
        self.create_and_test_file(state, entry)
1653
1654
    def test_update_symlink_to_dir(self):
1655
        """Symlink becomes a directory"""
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1656
        if not has_symlinks():
1657
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1658
        state, entry = self.get_state_with_a()
1659
        self.create_and_test_symlink(state, entry)
1660
        os.remove('a')
1661
        self.create_and_test_dir(state, entry)
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
1662
2255.10.7 by John Arbash Meinel
Some updates to how we handle the executable bit. In preparation for supporting Win32
1663
    def test__is_executable_win32(self):
1664
        state, entry = self.get_state_with_a()
1665
        self.build_tree(['a'])
1666
1667
        # Make sure we are using the win32 implementation of _is_executable
1668
        state._is_executable = state._is_executable_win32
1669
1670
        # The file on disk is not executable, but we are marking it as though
1671
        # it is. With _is_executable_win32 we ignore what is on disk.
1672
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1673
1674
        stat_value = os.lstat('a')
1675
        packed_stat = dirstate.pack_stat(stat_value)
1676
1677
        state.adjust_time(-10) # Make sure everything is new
1678
        # Make sure it wants to kkkkkkkk
1679
        state.update_entry(entry, abspath='a', stat_value=stat_value)
1680
1681
        # The row is updated, but the executable bit stays set.
1682
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1683
        self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1684
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1685
1686
class TestPackStat(TestCaseWithTransport):
1687
1688
    def assertPackStat(self, expected, stat_value):
1689
        """Check the packed and serialized form of a stat value."""
1690
        self.assertEqual(expected, dirstate.pack_stat(stat_value))
1691
1692
    def test_pack_stat_int(self):
1693
        st = _FakeStat(6859L, 1172758614, 1172758617, 777L, 6499538L, 0100644)
1694
        # Make sure that all parameters have an impact on the packed stat.
1695
        self.assertPackStat('AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
1696
        st.st_size = 7000L
1697
        #                ay0 => bWE
1698
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1699
        st.st_mtime = 1172758620
1700
        #                     4FZ => 4Fx
1701
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1702
        st.st_ctime = 1172758630
1703
        #                          uBZ => uBm
1704
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1705
        st.st_dev = 888L
1706
        #                                DCQ => DeA
1707
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
1708
        st.st_ino = 6499540L
1709
        #                                     LNI => LNQ
1710
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
1711
        st.st_mode = 0100744
1712
        #                                          IGk => IHk
1713
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
1714
1715
    def test_pack_stat_float(self):
1716
        """On some platforms mtime and ctime are floats.
1717
1718
        Make sure we don't get warnings or errors, and that we ignore changes <
1719
        1s
1720
        """
1721
        st = _FakeStat(7000L, 1172758614.0, 1172758617.0,
1722
                       777L, 6499538L, 0100644)
1723
        # These should all be the same as the integer counterparts
1724
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1725
        st.st_mtime = 1172758620.0
1726
        #                     FZF5 => FxF5
1727
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1728
        st.st_ctime = 1172758630.0
1729
        #                          uBZ => uBm
1730
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1731
        # fractional seconds are discarded, so no change from above
1732
        st.st_mtime = 1172758620.453
1733
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1734
        st.st_ctime = 1172758630.228
1735
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1736
1737
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
1738
class TestBisect(TestCaseWithDirState):
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1739
    """Test the ability to bisect into the disk format."""
1740
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1741
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1742
    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.
1743
        """Assert that bisecting for paths returns the right result.
1744
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1745
        :param expected_map: A map from key => entry value
1746
        :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.
1747
        :param state: The DirState object.
1748
        :param paths: A list of paths, these will automatically be split into
1749
                      (dir, name) tuples, and sorted according to how _bisect
1750
                      requires.
1751
        """
1752
        dir_names = sorted(osutils.split(p) for p in paths)
1753
        result = state._bisect(dir_names)
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1754
        # For now, results are just returned in whatever order we read them.
1755
        # We could sort by (dir, name, file_id) or something like that, but in
1756
        # 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
1757
        # extra overhead if we can avoid it. So sort everything to make sure
1758
        # equality is true
1759
        assert len(map_keys) == len(dir_names)
1760
        expected = {}
1761
        for dir_name, keys in zip(dir_names, map_keys):
1762
            if keys is None:
1763
                # This should not be present in the output
1764
                continue
1765
            expected[dir_name] = sorted(expected_map[k] for k in keys)
1766
1767
        for dir_name in result:
1768
            result[dir_name].sort()
1769
1770
        self.assertEqual(expected, result)
1771
1772
    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.
1773
        """Assert that bisecting for dirbblocks returns the right result.
1774
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1775
        :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
1776
        :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.
1777
            Something like [['a', 'b', 'f'], ['b/c', 'b/d']]
1778
        :param state: The DirState object.
1779
        :param paths: A list of directories
1780
        """
1781
        result = state._bisect_dirblocks(paths)
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1782
        assert len(map_keys) == len(paths)
1783
1784
        expected = {}
1785
        for path, keys in zip(paths, map_keys):
1786
            if keys is None:
1787
                # This should not be present in the output
1788
                continue
1789
            expected[path] = sorted(expected_map[k] for k in keys)
1790
        for path in result:
1791
            result[path].sort()
1792
1793
        self.assertEqual(expected, result)
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
1794
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1795
    def assertBisectRecursive(self, expected_map, map_keys, state, paths):
1796
        """Assert the return value of a recursive bisection.
1797
1798
        :param expected_map: A map from key => entry value
1799
        :param map_keys: A list of paths we expect to be returned.
1800
            Something like ['a', 'b', 'f', 'b/d', 'b/d2']
1801
        :param state: The DirState object.
1802
        :param paths: A list of files and directories. It will be broken up
1803
            into (dir, name) pairs and sorted before calling _bisect_recursive.
1804
        """
1805
        expected = {}
1806
        for key in map_keys:
1807
            entry = expected_map[key]
1808
            dir_name_id, trees_info = entry
1809
            expected[dir_name_id] = trees_info
1810
1811
        dir_names = sorted(osutils.split(p) for p in paths)
1812
        result = state._bisect_recursive(dir_names)
1813
1814
        self.assertEqual(expected, result)
1815
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1816
    def test_bisect_each(self):
1817
        """Find a single record using bisect."""
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1818
        tree, state, expected = self.create_basic_dirstate()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1819
1820
        # 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
1821
        self.assertBisect(expected, [['']], state, [''])
1822
        self.assertBisect(expected, [['a']], state, ['a'])
1823
        self.assertBisect(expected, [['b']], state, ['b'])
1824
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1825
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1826
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1827
        self.assertBisect(expected, [['f']], state, ['f'])
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1828
1829
    def test_bisect_multi(self):
1830
        """Bisect can be used to find multiple records at the same time."""
1831
        tree, state, expected = self.create_basic_dirstate()
1832
        # 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
1833
        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
1834
                          state, ['a', 'b', 'f'])
1835
        # ('', 'f') sorts before the others
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1836
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1837
                          state, ['b/d', 'b/d/e', 'f'])
1838
1839
    def test_bisect_one_page(self):
1840
        """Test bisect when there is only 1 page to read"""
1841
        tree, state, expected = self.create_basic_dirstate()
1842
        state._bisect_page_size = 5000
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1843
        self.assertBisect(expected,[['']], state, [''])
1844
        self.assertBisect(expected,[['a']], state, ['a'])
1845
        self.assertBisect(expected,[['b']], state, ['b'])
1846
        self.assertBisect(expected,[['b/c']], state, ['b/c'])
1847
        self.assertBisect(expected,[['b/d']], state, ['b/d'])
1848
        self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
1849
        self.assertBisect(expected,[['f']], state, ['f'])
1850
        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
1851
                          state, ['a', 'b', 'f'])
1852
        # ('', 'f') sorts before the others
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1853
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1854
                          state, ['b/d', 'b/d/e', 'f'])
1855
1856
    def test_bisect_duplicate_paths(self):
1857
        """When bisecting for a path, handle multiple entries."""
1858
        tree, state, expected = self.create_duplicated_dirstate()
1859
1860
        # 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
1861
        self.assertBisect(expected, [['']], state, [''])
1862
        self.assertBisect(expected, [['a', 'a2']], state, ['a'])
1863
        self.assertBisect(expected, [['b', 'b2']], state, ['b'])
1864
        self.assertBisect(expected, [['b/c', 'b/c2']], state, ['b/c'])
1865
        self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
1866
        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
1867
                          state, ['b/d/e'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1868
        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
1869
1870
    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.
1871
        """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
1872
        tree, state, expected = self.create_basic_dirstate()
1873
        state._bisect_page_size = 50
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1874
        self.assertBisect(expected, [None], state, ['b/e'])
1875
        self.assertBisect(expected, [['a']], state, ['a'])
1876
        self.assertBisect(expected, [['b']], state, ['b'])
1877
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1878
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1879
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1880
        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
1881
1882
    def test_bisect_missing(self):
1883
        """Test that bisect return None if it cannot find a path."""
1884
        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
1885
        self.assertBisect(expected, [None], state, ['foo'])
1886
        self.assertBisect(expected, [None], state, ['b/foo'])
1887
        self.assertBisect(expected, [None], state, ['bar/foo'])
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1888
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1889
        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
1890
                          state, ['a', 'foo', 'b/d'])
2255.2.127 by John Arbash Meinel
Expand the test suite to cover more cases.
1891
1892
    def test_bisect_rename(self):
1893
        """Check that we find a renamed row."""
1894
        tree, state, expected = self.create_renamed_dirstate()
1895
1896
        # 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
1897
        self.assertBisect(expected, [['a']], state, ['a'])
1898
        self.assertBisect(expected, [['b/g']], state, ['b/g'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1899
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1900
        self.assertBisect(expected, [['h']], state, ['h'])
1901
1902
        # What about b/d/e? shouldn't that also get 2 directory entries?
1903
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1904
        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.
1905
1906
    def test_bisect_dirblocks(self):
1907
        tree, state, expected = self.create_duplicated_dirstate()
1908
        self.assertBisectDirBlocks(expected,
1909
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2']], state, [''])
1910
        self.assertBisectDirBlocks(expected,
1911
            [['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
1912
        self.assertBisectDirBlocks(expected,
1913
            [['b/d/e', 'b/d/e2']], state, ['b/d'])
1914
        self.assertBisectDirBlocks(expected,
1915
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2'],
1916
             ['b/c', 'b/c2', 'b/d', 'b/d2'],
1917
             ['b/d/e', 'b/d/e2'],
1918
            ], state, ['', 'b', 'b/d'])
1919
1920
    def test_bisect_dirblocks_missing(self):
1921
        tree, state, expected = self.create_basic_dirstate()
1922
        self.assertBisectDirBlocks(expected, [['b/d/e'], None],
1923
            state, ['b/d', 'b/e'])
1924
        # Files don't show up in this search
1925
        self.assertBisectDirBlocks(expected, [None], state, ['a'])
1926
        self.assertBisectDirBlocks(expected, [None], state, ['b/c'])
1927
        self.assertBisectDirBlocks(expected, [None], state, ['c'])
1928
        self.assertBisectDirBlocks(expected, [None], state, ['b/d/e'])
1929
        self.assertBisectDirBlocks(expected, [None], state, ['f'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1930
1931
    def test_bisect_recursive_each(self):
1932
        tree, state, expected = self.create_basic_dirstate()
1933
        self.assertBisectRecursive(expected, ['a'], state, ['a'])
1934
        self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
1935
        self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
1936
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
1937
                                   state, ['b/d'])
1938
        self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
1939
                                   state, ['b'])
1940
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'f', 'b/c',
1941
                                              'b/d', 'b/d/e'],
1942
                                   state, [''])
1943
1944
    def test_bisect_recursive_multiple(self):
1945
        tree, state, expected = self.create_basic_dirstate()
1946
        self.assertBisectRecursive(expected, ['a', 'b/c'], state, ['a', 'b/c'])
1947
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
1948
                                   state, ['b/d', 'b/d/e'])
1949
1950
    def test_bisect_recursive_missing(self):
1951
        tree, state, expected = self.create_basic_dirstate()
1952
        self.assertBisectRecursive(expected, [], state, ['d'])
1953
        self.assertBisectRecursive(expected, [], state, ['b/e'])
1954
        self.assertBisectRecursive(expected, [], state, ['g'])
1955
        self.assertBisectRecursive(expected, ['a'], state, ['a', 'g'])
1956
1957
    def test_bisect_recursive_renamed(self):
1958
        tree, state, expected = self.create_renamed_dirstate()
1959
1960
        # Looking for either renamed item should find the other
1961
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
1962
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
1963
        # Looking in the containing directory should find the rename target,
1964
        # and anything in a subdir of the renamed target.
1965
        self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
1966
                                              'b/d/e', 'b/g', 'h', 'h/e'],
1967
                                   state, ['b'])
1968
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1969
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1970
class TestBisectDirblock(TestCase):
1971
    """Test that bisect_dirblock() returns the expected values.
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1972
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1973
    bisect_dirblock is intended to work like bisect.bisect_left() except it
1974
    knows it is working on dirblocks and that dirblocks are sorted by ('path',
1975
    'to', 'foo') chunks rather than by raw 'path/to/foo'.
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1976
    """
1977
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1978
    def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1979
        """Assert that bisect_split works like bisect_left on the split paths.
1980
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1981
        :param dirblocks: A list of (path, [info]) pairs.
1982
        :param split_dirblocks: A list of ((split, path), [info]) pairs.
1983
        :param path: The path we are indexing.
1984
1985
        All other arguments will be passed along.
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1986
        """
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1987
        bisect_split_idx = dirstate.bisect_dirblock(dirblocks, path,
1988
                                                 *args, **kwargs)
1989
        split_dirblock = (path.split('/'), [])
1990
        bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1991
                                             *args)
1992
        self.assertEqual(bisect_left_idx, bisect_split_idx,
1993
                         'bisect_split disagreed. %s != %s'
1994
                         ' for key %s'
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1995
                         % (bisect_left_idx, bisect_split_idx, path)
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
1996
                         )
1997
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
1998
    def paths_to_dirblocks(self, paths):
1999
        """Convert a list of paths into dirblock form.
2000
2001
        Also, ensure that the paths are in proper sorted order.
2002
        """
2003
        dirblocks = [(path, []) for path in paths]
2004
        split_dirblocks = [(path.split('/'), []) for path in paths]
2005
        self.assertEqual(sorted(split_dirblocks), split_dirblocks)
2006
        return dirblocks, split_dirblocks
2007
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2008
    def test_simple(self):
2009
        """In the simple case it works just like bisect_left"""
2010
        paths = ['', 'a', 'b', 'c', 'd']
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2011
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2012
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2013
            self.assertBisect(dirblocks, split_dirblocks, path)
2014
        self.assertBisect(dirblocks, split_dirblocks, '_')
2015
        self.assertBisect(dirblocks, split_dirblocks, 'aa')
2016
        self.assertBisect(dirblocks, split_dirblocks, 'bb')
2017
        self.assertBisect(dirblocks, split_dirblocks, 'cc')
2018
        self.assertBisect(dirblocks, split_dirblocks, 'dd')
2019
        self.assertBisect(dirblocks, split_dirblocks, 'a/a')
2020
        self.assertBisect(dirblocks, split_dirblocks, 'b/b')
2021
        self.assertBisect(dirblocks, split_dirblocks, 'c/c')
2022
        self.assertBisect(dirblocks, split_dirblocks, 'd/d')
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2023
2024
    def test_involved(self):
2025
        """This is where bisect_left diverges slightly."""
2026
        paths = ['', 'a',
2027
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2028
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2029
                 'a-a', 'a-z',
2030
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2031
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2032
                 'z-a', 'z-z',
2033
                ]
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2034
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2035
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2036
            self.assertBisect(dirblocks, split_dirblocks, path)
2255.8.3 by John Arbash Meinel
Add the ability to cache the split output
2037
2038
    def test_involved_cached(self):
2039
        """This is where bisect_left diverges slightly."""
2040
        paths = ['', 'a',
2041
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2042
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2043
                 'a-a', 'a-z',
2044
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2045
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2046
                 'z-a', 'z-z',
2047
                ]
2048
        cache = {}
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2049
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2255.8.3 by John Arbash Meinel
Add the ability to cache the split output
2050
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2051
            self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
2052
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
2053
2054
class TestDirstateValidation(TestCaseWithDirState):
2055
2056
    def test_validate_correct_dirstate(self):
2057
        state = self.create_complex_dirstate()
2058
        state._validate()
2059
        state.unlock()
2060
        # and make sure we can also validate with a read lock
2061
        state.lock_read()
2062
        try:
2063
            state._validate()
2064
        finally:
2065
            state.unlock()
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2066
2067
    def test_dirblock_not_sorted(self):
2068
        tree, state, expected = self.create_renamed_dirstate()
2069
        state._read_dirblocks_if_needed()
2070
        last_dirblock = state._dirblocks[-1]
2071
        # we're appending to the dirblock, but this name comes before some of
2072
        # the existing names; that's wrong
2073
        last_dirblock[1].append(
2074
            (('h', 'aaaa', 'a-id'),
2075
             [('a', '', 0, False, ''),
2076
              ('a', '', 0, False, '')]))
2077
        e = self.assertRaises(AssertionError,
2078
            state._validate)
2079
        self.assertContainsRe(str(e), 'not sorted')
2080
2081
    def test_dirblock_name_mismatch(self):
2082
        tree, state, expected = self.create_renamed_dirstate()
2083
        state._read_dirblocks_if_needed()
2084
        last_dirblock = state._dirblocks[-1]
2085
        # add an entry with the wrong directory name
2086
        last_dirblock[1].append(
2087
            (('', 'z', 'a-id'),
2088
             [('a', '', 0, False, ''),
2089
              ('a', '', 0, False, '')]))
2090
        e = self.assertRaises(AssertionError,
2091
            state._validate)
2092
        self.assertContainsRe(str(e),
2093
            "doesn't match directory name")
2094
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2095
    def test_dirblock_missing_rename(self):
2096
        tree, state, expected = self.create_renamed_dirstate()
2097
        state._read_dirblocks_if_needed()
2098
        last_dirblock = state._dirblocks[-1]
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2099
        # make another entry for a-id, without a correct 'r' pointer to
2100
        # the real occurrence in the working tree
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2101
        last_dirblock[1].append(
2102
            (('h', 'z', 'a-id'),
2103
             [('a', '', 0, False, ''),
2104
              ('a', '', 0, False, '')]))
2105
        e = self.assertRaises(AssertionError,
2106
            state._validate)
2107
        self.assertContainsRe(str(e),
2108
            'file a-id is absent in row')