/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()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
176
        del state
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)
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
561
            # Make sure everything is old enough
562
            state._sha_cutoff_time()
563
            state._cutoff_time += 10
2353.4.5 by John Arbash Meinel
Update DirState to use the new 'temporary_write_lock', and add tests that it works.
564
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
565
            # We should have gotten a real sha1
566
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
567
                             sha1sum)
568
569
            # The dirblock has been updated
570
            self.assertEqual(sha1sum, entry[1][0][1])
571
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
572
                             state._dirblock_state)
573
574
            del entry
575
            # Now, since we are the only one holding a lock, we should be able
576
            # to save and have it written to disk
577
            state.save()
578
        finally:
579
            state.unlock()
580
581
        # Re-open the file, and ensure that the state has been updated.
582
        state = dirstate.DirState.on_file('dirstate')
583
        state.lock_read()
584
        try:
585
            entry = state._get_entry(0, path_utf8='a-file')
586
            self.assertEqual(sha1sum, entry[1][0][1])
587
        finally:
588
            state.unlock()
589
590
    def test_save_fails_quietly_if_locked(self):
591
        """If dirstate is locked, save will fail without complaining."""
592
        self.build_tree(['a-file'])
593
        state = dirstate.DirState.initialize('dirstate')
594
        try:
595
            # No stat and no sha1 sum.
596
            state.add('a-file', 'a-file-id', 'file', None, '')
597
            state.save()
598
        finally:
599
            state.unlock()
600
601
        state = dirstate.DirState.on_file('dirstate')
602
        state.lock_read()
603
        try:
604
            entry = state._get_entry(0, path_utf8='a-file')
605
            sha1sum = state.update_entry(entry, 'a-file', os.lstat('a-file'))
606
            # We should have gotten a real sha1
607
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
608
                             sha1sum)
609
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
610
                             state._dirblock_state)
611
612
            # Now, before we try to save, grab another dirstate, and take out a
613
            # read lock.
614
            # TODO: jam 20070315 Ideally this would be locked by another
615
            #       process. To make sure the file is really OS locked.
616
            state2 = dirstate.DirState.on_file('dirstate')
617
            state2.lock_read()
618
            try:
619
                # This won't actually write anything, because it couldn't grab
620
                # a write lock. But it shouldn't raise an error, either.
621
                # TODO: jam 20070315 We should probably distinguish between
622
                #       being dirty because of 'update_entry'. And dirty
623
                #       because of real modification. So that save() *does*
624
                #       raise a real error if it fails when we have real
625
                #       modifications.
626
                state.save()
627
            finally:
628
                state2.unlock()
629
        finally:
630
            state.unlock()
631
        
632
        # The file on disk should not be modified.
633
        state = dirstate.DirState.on_file('dirstate')
634
        state.lock_read()
635
        try:
636
            entry = state._get_entry(0, path_utf8='a-file')
637
            self.assertEqual('', entry[1][0][1])
638
        finally:
639
            state.unlock()
640
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
641
642
class TestDirStateInitialize(TestCaseWithDirState):
1852.13.15 by Robert Collins
Ensure Format4 working trees start with a dirstate.
643
644
    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.
645
        expected_result = ([], [
646
            (('', '', 'TREE_ROOT'), # common details
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
647
             [('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.
648
             ])
649
            ])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
650
        state = dirstate.DirState.initialize('dirstate')
651
        try:
652
            self.assertIsInstance(state, dirstate.DirState)
653
            lines = state.get_lines()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
654
        finally:
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
655
            state.unlock()
2425.3.1 by John Arbash Meinel
Change the DirState.test_initialize test so that we don't try to read a locked file.
656
        # On win32 you can't read from a locked file, even within the same
657
        # process. So we have to unlock and release before we check the file
658
        # contents.
659
        self.assertFileEqual(''.join(lines), 'dirstate')
660
        state.lock_read() # check_state_with_reopen will unlock
661
        self.check_state_with_reopen(expected_result, state)
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
662
663
664
class TestDirStateManipulations(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
665
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.
666
    def test_set_state_from_inventory_no_content_no_parents(self):
667
        # setting the current inventory is a slow but important api to support.
668
        tree1 = self.make_branch_and_memory_tree('tree1')
669
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
670
        try:
671
            tree1.add('')
672
            revid1 = tree1.commit('foo').encode('utf8')
673
            root_id = tree1.inventory.root.file_id
674
            inv = tree1.inventory
675
        finally:
676
            tree1.unlock()
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
677
        expected_result = [], [
678
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
679
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
680
        state = dirstate.DirState.initialize('dirstate')
681
        try:
682
            state.set_state_from_inventory(inv)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
683
            self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
684
                             state._header_state)
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
685
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
686
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
687
        except:
688
            state.unlock()
689
            raise
690
        else:
691
            # This will unlock it
692
            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.
693
2487.1.1 by John Arbash Meinel
Adding a (broken) test that set_state_from_inventory works
694
    def test_set_state_from_inventory_mixed_paths(self):
695
        tree1 = self.make_branch_and_tree('tree1')
696
        self.build_tree(['tree1/a/', 'tree1/a/b/', 'tree1/a-b/',
697
                         'tree1/a/b/foo', 'tree1/a-b/bar'])
698
        tree1.lock_write()
699
        try:
700
            tree1.add(['a', 'a/b', 'a-b', 'a/b/foo', 'a-b/bar'],
701
                      ['a-id', 'b-id', 'a-b-id', 'foo-id', 'bar-id'])
702
            tree1.commit('rev1', rev_id='rev1')
703
            root_id = tree1.get_root_id()
704
            inv = tree1.inventory
705
        finally:
706
            tree1.unlock()
707
        expected_result1 = [('', '', root_id, 'd'),
708
                            ('', 'a', 'a-id', 'd'),
709
                            ('', 'a-b', 'a-b-id', 'd'),
710
                            ('a', 'b', 'b-id', 'd'),
711
                            ('a/b', 'foo', 'foo-id', 'f'),
712
                            ('a-b', 'bar', 'bar-id', 'f'),
713
                           ]
714
        expected_result2 = [('', '', root_id, 'd'),
715
                            ('', 'a', 'a-id', 'd'),
716
                            ('', 'a-b', 'a-b-id', 'd'),
717
                            ('a-b', 'bar', 'bar-id', 'f'),
718
                           ]
719
        state = dirstate.DirState.initialize('dirstate')
720
        try:
721
            state.set_state_from_inventory(inv)
722
            values = []
723
            for entry in state._iter_entries():
724
                values.append(entry[0] + entry[1][0][:1])
725
            self.assertEqual(expected_result1, values)
726
            del inv['b-id']
727
            state.set_state_from_inventory(inv)
728
            values = []
729
            for entry in state._iter_entries():
730
                values.append(entry[0] + entry[1][0][:1])
731
            self.assertEqual(expected_result2, values)
732
        finally:
733
            state.unlock()
734
2255.2.4 by Robert Collins
Snapshot dirstate development
735
    def test_set_path_id_no_parents(self):
736
        """The id of a path can be changed trivally with no parents."""
737
        state = dirstate.DirState.initialize('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
738
        try:
739
            # check precondition to be sure the state does change appropriately.
740
            self.assertEqual(
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
741
                [(('', '', 'TREE_ROOT'), [('d', '', 0, False,
742
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])],
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
743
                list(state._iter_entries()))
744
            state.set_path_id('', 'foobarbaz')
745
            expected_rows = [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
746
                (('', '', 'foobarbaz'), [('d', '', 0, False,
747
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
748
            self.assertEqual(expected_rows, list(state._iter_entries()))
749
            # should work across save too
750
            state.save()
751
        finally:
752
            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.
753
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
754
        state.lock_read()
755
        try:
2323.6.13 by Martin Pool
Fix some tests that need to lock dirstate before validating
756
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
757
            self.assertEqual(expected_rows, list(state._iter_entries()))
758
        finally:
759
            state.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
760
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
761
    def test_set_path_id_with_parents(self):
762
        """Set the root file id in a dirstate with parents"""
763
        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
764
        # in case the default tree format uses a different root id
765
        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
766
        mt.commit('foo', rev_id='parent-revid')
767
        rt = mt.branch.repository.revision_tree('parent-revid')
768
        state = dirstate.DirState.initialize('dirstate')
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
769
        state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
770
        try:
771
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
772
            state.set_path_id('', 'foobarbaz')
2255.2.177 by Martin Pool
merge dirstate sorting fix, add more validation tests
773
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
774
            # now see that it is what we expected
775
            expected_rows = [
776
                (('', '', 'TREE_ROOT'),
777
                    [('a', '', 0, False, ''),
778
                     ('d', '', 0, False, 'parent-revid'),
779
                     ]),
780
                (('', '', 'foobarbaz'),
781
                    [('d', '', 0, False, ''),
782
                     ('a', '', 0, False, ''),
783
                     ]),
784
                ]
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
785
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
786
            self.assertEqual(expected_rows, list(state._iter_entries()))
787
            # should work across save too
788
            state.save()
789
        finally:
790
            state.unlock()
791
        # now flush & check we get the same
792
        state = dirstate.DirState.on_file('dirstate')
793
        state.lock_read()
794
        try:
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
795
            state._validate()
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
796
            self.assertEqual(expected_rows, list(state._iter_entries()))
797
        finally:
798
            state.unlock()
2255.11.2 by Martin Pool
Add more dirstate root-id-changing tests
799
        # now change within an existing file-backed state
800
        state.lock_write()
801
        try:
802
            state._validate()
803
            state.set_path_id('', 'tree-root-2')
804
            state._validate()
805
        finally:
806
            state.unlock()
807
2255.7.68 by Martin Pool
Add a test for setting the root id in a dirstate with parent trees
808
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.
809
    def test_set_parent_trees_no_content(self):
810
        # set_parent_trees is a slow but important api to support.
811
        tree1 = self.make_branch_and_memory_tree('tree1')
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
812
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
813
        try:
814
            tree1.add('')
815
            revid1 = tree1.commit('foo')
816
        finally:
817
            tree1.unlock()
2255.2.4 by Robert Collins
Snapshot dirstate development
818
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
819
        tree2 = MemoryTree.create_on_branch(branch2)
2255.2.2 by Robert Collins
Partial updates for API changes in trunk.
820
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
821
        try:
822
            revid2 = tree2.commit('foo')
823
            root_id = tree2.inventory.root.file_id
824
        finally:
825
            tree2.unlock()
826
        state = dirstate.DirState.initialize('dirstate')
827
        try:
828
            state.set_path_id('', root_id)
829
            state.set_parent_trees(
830
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
831
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
832
                 ('ghost-rev', None)),
833
                ['ghost-rev'])
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
834
            # check we can reopen and use the dirstate after setting parent
835
            # trees.
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
836
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
837
            state.save()
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
838
            state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
839
        finally:
840
            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.
841
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
842
        state.lock_write()
843
        try:
844
            self.assertEqual([revid1, revid2, 'ghost-rev'],
845
                             state.get_parent_ids())
846
            # iterating the entire state ensures that the state is parsable.
847
            list(state._iter_entries())
848
            # be sure that it sets not appends - change it
849
            state.set_parent_trees(
850
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
851
                 ('ghost-rev', None)),
852
                ['ghost-rev'])
853
            # and now put it back.
854
            state.set_parent_trees(
855
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
856
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
857
                 ('ghost-rev', tree2.branch.repository.revision_tree(None))),
858
                ['ghost-rev'])
859
            self.assertEqual([revid1, revid2, 'ghost-rev'],
860
                             state.get_parent_ids())
861
            # the ghost should be recorded as such by set_parent_trees.
862
            self.assertEqual(['ghost-rev'], state.get_ghosts())
863
            self.assertEqual(
864
                [(('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
865
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
866
                  ('d', '', 0, False, revid1),
867
                  ('d', '', 0, False, revid2)
868
                  ])],
869
                list(state._iter_entries()))
870
        finally:
871
            state.unlock()
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
872
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
873
    def test_set_parent_trees_file_missing_from_tree(self):
874
        # 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
875
        # 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
876
        # separate trees.
877
        # set_parent_trees is a slow but important api to support.
878
        tree1 = self.make_branch_and_memory_tree('tree1')
879
        tree1.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
880
        try:
881
            tree1.add('')
882
            tree1.add(['a file'], ['file-id'], ['file'])
883
            tree1.put_file_bytes_non_atomic('file-id', 'file-content')
884
            revid1 = tree1.commit('foo')
885
        finally:
886
            tree1.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
887
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
888
        tree2 = MemoryTree.create_on_branch(branch2)
889
        tree2.lock_write()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
890
        try:
891
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
892
            revid2 = tree2.commit('foo')
893
            root_id = tree2.inventory.root.file_id
894
        finally:
895
            tree2.unlock()
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
896
        # check the layout in memory
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
897
        expected_result = [revid1.encode('utf8'), revid2.encode('utf8')], [
898
            (('', '', root_id), [
2255.2.124 by John Arbash Meinel
Remove direct access to Dirstate prefering dirstate.Dirstate
899
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
900
             ('d', '', 0, False, revid1.encode('utf8')),
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
901
             ('d', '', 0, False, revid2.encode('utf8'))
902
             ]),
2255.2.87 by Robert Collins
core dirstate tests passing with new structure.
903
            (('', 'a file', 'file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
904
             ('a', '', 0, False, ''),
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
905
             ('f', '2439573625385400f2a669657a7db6ae7515d371', 12, False,
906
              revid1.encode('utf8')),
907
             ('f', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False,
908
              revid2.encode('utf8'))
909
             ])
2255.2.9 by Robert Collins
Dirstate: Fix setting of parent trees to record data about entries not in
910
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
911
        state = dirstate.DirState.initialize('dirstate')
912
        try:
913
            state.set_path_id('', root_id)
914
            state.set_parent_trees(
915
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
916
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
917
                 ), [])
918
        except:
919
            state.unlock()
920
            raise
921
        else:
922
            # check_state_with_reopen will unlock
923
            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
924
1852.13.20 by Robert Collins
Steps toward an object model.
925
    ### add a path via _set_data - so we dont need delta work, just
926
    # 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.
927
1852.13.25 by Robert Collins
Snapshot state
928
    def test_add_path_to_root_no_parents_all_data(self):
929
        # The most trivial addition of a path is when there are no parents and
930
        # its in the root and all data about the file is supplied
931
        self.build_tree(['a file'])
932
        stat = os.lstat('a file')
933
        # the 1*20 is the sha1 pretend value.
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
934
        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.
935
        expected_entries = [
936
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
937
             ('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.
938
             ]),
939
            (('', 'a file', 'a file id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
940
             ('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.
941
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
942
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
943
        try:
944
            state.add('a file', 'a file id', 'file', stat, '1'*20)
945
            # having added it, it should be in the output of iter_entries.
946
            self.assertEqual(expected_entries, list(state._iter_entries()))
947
            # saving and reloading should not affect this.
948
            state.save()
949
        finally:
950
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
951
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
952
        state.lock_read()
953
        try:
954
            self.assertEqual(expected_entries, list(state._iter_entries()))
955
        finally:
956
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
957
958
    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.
959
        """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.
960
961
        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.
962
        once dirstate is stable and if it is merged with WorkingTree3, consider
963
        removing this copy of the test.
964
        """
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
965
        self.build_tree(['unversioned/', 'unversioned/a file'])
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
966
        state = dirstate.DirState.initialize('dirstate')
967
        try:
968
            self.assertRaises(errors.NotVersionedError, state.add,
969
                'unversioned/a file', 'a file id', 'file', None, None)
970
        finally:
971
            state.unlock()
972
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
973
    def test_add_directory_to_root_no_parents_all_data(self):
974
        # The most trivial addition of a dir is when there are no parents and
975
        # its in the root and all data about the file is supplied
976
        self.build_tree(['a dir/'])
977
        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.
978
        expected_entries = [
979
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
980
             ('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.
981
             ]),
982
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
983
             ('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.
984
             ]),
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
985
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
986
        state = dirstate.DirState.initialize('dirstate')
987
        try:
988
            state.add('a dir', 'a dir id', 'directory', stat, None)
989
            # having added it, it should be in the output of iter_entries.
990
            self.assertEqual(expected_entries, list(state._iter_entries()))
991
            # saving and reloading should not affect this.
992
            state.save()
993
        finally:
994
            state.unlock()
2255.2.13 by Robert Collins
Test adding of directories to the root of a dirstate.
995
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
996
        state.lock_read()
2255.7.78 by Martin Pool
Add DirState._validate and call from the tests
997
        state._validate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
998
        try:
999
            self.assertEqual(expected_entries, list(state._iter_entries()))
1000
        finally:
1001
            state.unlock()
1852.13.25 by Robert Collins
Snapshot state
1002
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.
1003
    def test_add_symlink_to_root_no_parents_all_data(self):
1004
        # The most trivial addition of a symlink when there are no parents and
1005
        # its in the root and all data about the file is supplied
2321.3.8 by Alexander Belchenko
Cleanup patch after John's review
1006
        # 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
1007
        if not has_symlinks():
1008
            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.
1009
        os.symlink('target', 'a link')
1010
        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.
1011
        expected_entries = [
1012
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1013
             ('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.
1014
             ]),
1015
            (('', 'a link', 'a link id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1016
             ('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.
1017
             ]),
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.
1018
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1019
        state = dirstate.DirState.initialize('dirstate')
1020
        try:
1021
            state.add('a link', 'a link id', 'symlink', stat, 'target')
1022
            # having added it, it should be in the output of iter_entries.
1023
            self.assertEqual(expected_entries, list(state._iter_entries()))
1024
            # saving and reloading should not affect this.
1025
            state.save()
1026
        finally:
1027
            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.
1028
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1029
        state.lock_read()
1030
        try:
1031
            self.assertEqual(expected_entries, list(state._iter_entries()))
1032
        finally:
1033
            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.
1034
1035
    def test_add_directory_and_child_no_parents_all_data(self):
1036
        # after adding a directory, we should be able to add children to it.
1037
        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.
1038
        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.
1039
        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.
1040
        expected_entries = [
1041
            (('', '', 'TREE_ROOT'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1042
             ('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.
1043
             ]),
1044
            (('', 'a dir', 'a dir id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1045
             ('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.
1046
             ]),
1047
            (('a dir', 'a file', 'a file id'), [
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1048
             ('f', '1'*20, 25, False,
1049
              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.
1050
             ]),
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.
1051
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1052
        state = dirstate.DirState.initialize('dirstate')
1053
        try:
1054
            state.add('a dir', 'a dir id', 'directory', dirstat, None)
1055
            state.add('a dir/a file', 'a file id', 'file', filestat, '1'*20)
1056
            # added it, it should be in the output of iter_entries.
1057
            self.assertEqual(expected_entries, list(state._iter_entries()))
1058
            # saving and reloading should not affect this.
1059
            state.save()
1060
        finally:
1061
            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.
1062
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1063
        state.lock_read()
1064
        try:
1065
            self.assertEqual(expected_entries, list(state._iter_entries()))
1066
        finally:
1067
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1068
2255.7.93 by Martin Pool
Add support for tree-references in dirstate
1069
    def test_add_tree_reference(self):
1070
        # make a dirstate and add a tree reference
1071
        state = dirstate.DirState.initialize('dirstate')
1072
        expected_entry = (
1073
            ('', 'subdir', 'subdir-id'),
1074
            [('t', 'subtree-123123', 0, False,
1075
              'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')],
1076
            )
1077
        try:
1078
            state.add('subdir', 'subdir-id', 'tree-reference', None, 'subtree-123123')
1079
            entry = state._get_entry(0, 'subdir-id', 'subdir')
1080
            self.assertEqual(entry, expected_entry)
1081
            state._validate()
1082
            state.save()
1083
        finally:
1084
            state.unlock()
1085
        # now check we can read it back
1086
        state.lock_read()
1087
        state._validate()
1088
        try:
1089
            entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1090
            self.assertEqual(entry, entry2)
1091
            self.assertEqual(entry, expected_entry)
1092
            # and lookup by id should work too
1093
            entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1094
            self.assertEqual(entry, expected_entry)
1095
        finally:
1096
            state.unlock()
1097
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1098
    def test_add_forbidden_names(self):
1099
        state = dirstate.DirState.initialize('dirstate')
2255.2.233 by John Arbash Meinel
DirState.initialize returns a locked state, unlock as part of cleanup.
1100
        self.addCleanup(state.unlock)
2255.2.225 by Martin Pool
Prohibit dirstate from getting entries called ..
1101
        self.assertRaises(errors.BzrError,
1102
            state.add, '.', 'ass-id', 'directory', None, None)
1103
        self.assertRaises(errors.BzrError,
1104
            state.add, '..', 'ass-id', 'directory', None, None)
1105
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1106
1107
class TestGetLines(TestCaseWithDirState):
1852.13.19 by Robert Collins
Get DirState objects roundtripping an add of a ghost tree.
1108
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.
1109
    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.
1110
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1111
        try:
2255.7.20 by John Arbash Meinel
update test for format 3, and enable caching of path split while lock is held.
1112
            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.
1113
                'crc32: 41262208\n',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1114
                'num_entries: 2\n',
1115
                '0\x00\n\x00'
1116
                '0\x00\n\x00'
1117
                '\x00\x00a-root-value\x00'
1118
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1119
                '\x00subdir\x00subdir-id\x00'
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1120
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1121
                ], state.get_lines())
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1122
        finally:
1123
            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.
1124
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1125
    def test_entry_to_line(self):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1126
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1127
        try:
1128
            self.assertEqual(
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1129
                '\x00\x00a-root-value\x00d\x00\x000\x00n'
1130
                '\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1131
                state._entry_to_line(state._dirblocks[0][1][0]))
1132
        finally:
1133
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1134
1135
    def test_entry_to_line_with_parent(self):
1136
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1137
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1138
            ('d', '', 0, False, packed_stat), # current tree details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1139
             # first: a pointer to the current location
1140
            ('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.
1141
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1142
        state = dirstate.DirState.initialize('dirstate')
1143
        try:
1144
            self.assertEqual(
1145
                '\x00\x00a-root-value\x00'
1146
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1147
                'a\x00dirname/basename\x000\x00n\x00',
1148
                state._entry_to_line(root_entry))
1149
        finally:
1150
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1151
1152
    def test_entry_to_line_with_two_parents_at_different_paths(self):
1153
        # / in the tree, at / in one parent and /dirname/basename in the other.
1154
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1155
        root_entry = ('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1156
            ('d', '', 0, False, packed_stat), # current tree details
1157
            ('d', '', 0, False, 'rev_id'), # first parent details
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1158
             # second: a pointer to the current location
1159
            ('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.
1160
            ]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1161
        state = dirstate.DirState.initialize('dirstate')
1162
        try:
1163
            self.assertEqual(
1164
                '\x00\x00a-root-value\x00'
1165
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1166
                'd\x00\x000\x00n\x00rev_id\x00'
1167
                'a\x00dirname/basename\x000\x00n\x00',
1168
                state._entry_to_line(root_entry))
1169
        finally:
1170
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1171
1172
    def test_iter_entries(self):
1173
        # 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.
1174
        # this is for get_lines to be easy to read.
1175
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1176
        dirblocks = []
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1177
        root_entries = [(('', '', 'a-root-value'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1178
            ('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.
1179
            ])]
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1180
        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.
1181
        # 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.
1182
        subdir_entry = ('', 'subdir', 'subdir-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1183
            ('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.
1184
            ]
1185
        afile_entry = ('', 'afile', 'afile-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1186
            ('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.
1187
            ]
1188
        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.
1189
        # 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.
1190
        file_entry2 = ('subdir', '2file', '2file-id'), [
2255.2.113 by John Arbash Meinel
545ms, 600ms: Switch memory model from storing kind to using minikind
1191
            ('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.
1192
            ]
1193
        dirblocks.append(('subdir', [file_entry2]))
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1194
        state = dirstate.DirState.initialize('dirstate')
1195
        try:
1196
            state._set_data([], dirblocks)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1197
            expected_entries = [root_entries[0], subdir_entry, afile_entry,
1198
                                file_entry2]
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1199
            self.assertEqual(expected_entries, list(state._iter_entries()))
1200
        finally:
1201
            state.unlock()
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1202
1203
1204
class TestGetBlockRowIndex(TestCaseWithDirState):
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1205
1206
    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.
1207
        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.
1208
        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.
1209
            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.
1210
        if dir_present:
1211
            block = state._dirblocks[block_index]
1212
            self.assertEqual(dirname, block[0])
1213
        if dir_present and file_present:
1214
            row = state._dirblocks[block_index][1][row_index]
1215
            self.assertEqual(dirname, row[0][0])
1216
            self.assertEqual(basename, row[0][1])
1217
1218
    def test_simple_structure(self):
1219
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1220
        self.addCleanup(state.unlock)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1221
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
1222
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
1223
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
1224
        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
1225
        self.assertBlockRowIndexEqual(2, 0, False, False, state,
1226
                                      'subdir', 'foo', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1227
1228
    def test_complex_structure_exists(self):
1229
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1230
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1231
        # Make sure we can find everything that exists
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1232
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1233
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
1234
        self.assertBlockRowIndexEqual(1, 1, True, True, state, '', 'b', 0)
1235
        self.assertBlockRowIndexEqual(1, 2, True, True, state, '', 'c', 0)
1236
        self.assertBlockRowIndexEqual(1, 3, True, True, state, '', 'd', 0)
1237
        self.assertBlockRowIndexEqual(2, 0, True, True, state, 'a', 'e', 0)
1238
        self.assertBlockRowIndexEqual(2, 1, True, True, state, 'a', 'f', 0)
1239
        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
1240
        self.assertBlockRowIndexEqual(3, 1, True, True, state,
1241
                                      'b', 'h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1242
1243
    def test_complex_structure_missing(self):
1244
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1245
        self.addCleanup(state.unlock)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1246
        # Make sure things would be inserted in the right locations
1247
        # '_' comes before 'a'
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1248
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1249
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', '_', 0)
1250
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'aa', 0)
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1251
        self.assertBlockRowIndexEqual(1, 4, True, False, state,
1252
                                      '', 'h\xc3\xa5', 0)
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1253
        self.assertBlockRowIndexEqual(2, 0, False, False, state, '_', 'a', 0)
1254
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'aa', 'a', 0)
1255
        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.
1256
        # This would be inserted between a/ and b/
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1257
        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.
1258
        # Put at the end
2255.2.96 by Robert Collins
Restore dirstate to all tests passing condition.
1259
        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.
1260
1261
1262
class TestGetEntry(TestCaseWithDirState):
1263
1264
    def assertEntryEqual(self, dirname, basename, file_id, state, path, index):
1265
        """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.
1266
        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.
1267
        if file_id is None:
1268
            self.assertEqual((None, None), entry)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1269
        else:
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1270
            cur = entry[0]
1271
            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.
1272
1273
    def test_simple_structure(self):
1274
        state = self.create_dirstate_with_root_and_subdir()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1275
        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.
1276
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1277
        self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
1278
        self.assertEntryEqual(None, None, None, state, 'missing', 0)
1279
        self.assertEntryEqual(None, None, None, state, 'missing/foo', 0)
1280
        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.
1281
1282
    def test_complex_structure_exists(self):
1283
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1284
        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.
1285
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1286
        self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
1287
        self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
1288
        self.assertEntryEqual('', 'c', 'c-file', state, 'c', 0)
1289
        self.assertEntryEqual('', 'd', 'd-file', state, 'd', 0)
1290
        self.assertEntryEqual('a', 'e', 'e-dir', state, 'a/e', 0)
1291
        self.assertEntryEqual('a', 'f', 'f-file', state, 'a/f', 0)
1292
        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
1293
        self.assertEntryEqual('b', 'h\xc3\xa5', 'h-\xc3\xa5-file', state,
1294
                              'b/h\xc3\xa5', 0)
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1295
1296
    def test_complex_structure_missing(self):
1297
        state = self.create_complex_dirstate()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1298
        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.
1299
        self.assertEntryEqual(None, None, None, state, '_', 0)
1300
        self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
1301
        self.assertEntryEqual(None, None, None, state, 'a/b', 0)
1302
        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.
1303
2255.2.85 by Robert Collins
[BROKEN] Partial conversion to new dirstate structure, please continue on the tests matching dirstate from here.
1304
    def test_get_entry_uninitialized(self):
1305
        """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.
1306
        state = self.create_dirstate_with_root()
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1307
        try:
1308
            state.save()
1309
        finally:
1310
            state.unlock()
2255.2.66 by John Arbash Meinel
Move _get_row and _get_block_row_index into Dirstate itself.
1311
        del state
1312
        state = dirstate.DirState.on_file('dirstate')
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1313
        state.lock_read()
1314
        try:
2255.2.123 by John Arbash Meinel
Simple line wrapping cleanup in test_dirstate.py
1315
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1316
                             state._header_state)
1317
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1318
                             state._dirblock_state)
2255.5.1 by John Arbash Meinel
Update the dirstate tests to lock and unlock properly.
1319
            self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1320
        finally:
1321
            state.unlock()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1322
1323
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1324
class TestDirstateSortOrder(TestCaseWithTransport):
1325
    """Test that DirState adds entries in the right order."""
1326
1327
    def test_add_sorting(self):
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1328
        """Add entries in lexicographical order, we get path sorted order.
1329
1330
        This tests it to a depth of 4, to make sure we don't just get it right
1331
        at a single depth. 'a/a' should come before 'a-a', even though it
1332
        doesn't lexicographically.
1333
        """
1334
        dirs = ['a', 'a/a', 'a/a/a', 'a/a/a/a',
1335
                '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.
1336
               ]
1337
        null_sha = ''
1338
        state = dirstate.DirState.initialize('dirstate')
1339
        self.addCleanup(state.unlock)
1340
1341
        fake_stat = os.stat('dirstate')
1342
        for d in dirs:
1343
            d_id = d.replace('/', '_')+'-id'
1344
            file_path = d + '/f'
1345
            file_id = file_path.replace('/', '_')+'-id'
1346
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1347
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1348
1349
        expected = ['', '', 'a',
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1350
                'a/a', 'a/a/a', 'a/a/a/a',
1351
                '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.
1352
               ]
2255.7.21 by John Arbash Meinel
Get iter_changes working again, by fixing set_parent_trees to
1353
        split = lambda p:p.split('/')
1354
        self.assertEqual(sorted(expected, key=split), expected)
1355
        dirblock_names = [d[0] for d in state._dirblocks]
1356
        self.assertEqual(expected, dirblock_names)
1357
1358
    def test_set_parent_trees_correct_order(self):
1359
        """After calling set_parent_trees() we should maintain the order."""
1360
        dirs = ['a', 'a-a', 'a/a']
1361
        null_sha = ''
1362
        state = dirstate.DirState.initialize('dirstate')
1363
        self.addCleanup(state.unlock)
1364
1365
        fake_stat = os.stat('dirstate')
1366
        for d in dirs:
1367
            d_id = d.replace('/', '_')+'-id'
1368
            file_path = d + '/f'
1369
            file_id = file_path.replace('/', '_')+'-id'
1370
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1371
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1372
1373
        expected = ['', '', 'a', 'a/a', 'a-a']
1374
        dirblock_names = [d[0] for d in state._dirblocks]
1375
        self.assertEqual(expected, dirblock_names)
1376
1377
        # *really* cheesy way to just get an empty tree
1378
        repo = self.make_repository('repo')
1379
        empty_tree = repo.revision_tree(None)
1380
        state.set_parent_trees([('null:', empty_tree)], [])
1381
2255.8.5 by John Arbash Meinel
Add a test that dirstate adds records in the right order.
1382
        dirblock_names = [d[0] for d in state._dirblocks]
1383
        self.assertEqual(expected, dirblock_names)
1384
1385
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1386
class InstrumentedDirState(dirstate.DirState):
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1387
    """An DirState with instrumented sha1 functionality."""
1388
1389
    def __init__(self, path):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1390
        super(InstrumentedDirState, self).__init__(path)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1391
        self._time_offset = 0
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1392
        self._log = []
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1393
1394
    def _sha_cutoff_time(self):
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1395
        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.
1396
        self._cutoff_time = timestamp + self._time_offset
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1397
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1398
    def _sha1_file(self, abspath, entry):
1399
        self._log.append(('sha1', abspath))
1400
        return super(InstrumentedDirState, self)._sha1_file(abspath, entry)
1401
1402
    def _read_link(self, abspath, old_link):
1403
        self._log.append(('read_link', abspath, old_link))
1404
        return super(InstrumentedDirState, self)._read_link(abspath, old_link)
1405
1406
    def _lstat(self, abspath, entry):
1407
        self._log.append(('lstat', abspath))
1408
        return super(InstrumentedDirState, self)._lstat(abspath, entry)
1409
1410
    def _is_executable(self, mode, old_executable):
1411
        self._log.append(('is_exec', mode, old_executable))
1412
        return super(InstrumentedDirState, self)._is_executable(mode,
1413
                                                                old_executable)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1414
1415
    def adjust_time(self, secs):
1416
        """Move the clock forward or back.
1417
1418
        :param secs: The amount to adjust the clock by. Positive values make it
1419
        seem as if we are in the future, negative values make it seem like we
1420
        are in the past.
1421
        """
1422
        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.
1423
        self._cutoff_time = None
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1424
1425
1426
class _FakeStat(object):
1427
    """A class with the same attributes as a real stat result."""
1428
1429
    def __init__(self, size, mtime, ctime, dev, ino, mode):
1430
        self.st_size = size
1431
        self.st_mtime = mtime
1432
        self.st_ctime = ctime
1433
        self.st_dev = dev
1434
        self.st_ino = ino
1435
        self.st_mode = mode
1436
1437
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1438
class TestUpdateEntry(TestCaseWithDirState):
1439
    """Test the DirState.update_entry functions"""
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1440
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1441
    def get_state_with_a(self):
1442
        """Create a DirState tracking a single object named 'a'"""
1443
        state = InstrumentedDirState.initialize('dirstate')
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1444
        self.addCleanup(state.unlock)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1445
        state.add('a', 'a-id', 'file', None, '')
1446
        entry = state._get_entry(0, path_utf8='a')
1447
        return state, entry
1448
1449
    def test_update_entry(self):
1450
        state, entry = self.get_state_with_a()
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1451
        self.build_tree(['a'])
1452
        # Add one where we don't provide the stat or sha already
1453
        self.assertEqual(('', 'a', 'a-id'), entry[0])
1454
        self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1455
                         entry[1])
1456
        # Flush the buffers to disk
1457
        state.save()
1458
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1459
                         state._dirblock_state)
1460
1461
        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.
1462
        packed_stat = dirstate.pack_stat(stat_value)
1463
        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,
1464
                                          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.
1465
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1466
                         link_or_sha1)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1467
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1468
        # The dirblock entry should not cache the file's sha1
1469
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1470
                         entry[1])
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1471
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1472
                         state._dirblock_state)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1473
        mode = stat_value.st_mode
1474
        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,
1475
1476
        state.save()
1477
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1478
                         state._dirblock_state)
1479
1480
        # If we do it again right away, we don't know if the file has changed
1481
        # so we will re-read the file. Roll the clock back so the file is
1482
        # guaranteed to look too new.
1483
        state.adjust_time(-10)
1484
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1485
        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,
1486
                                          stat_value=stat_value)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1487
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1488
                          ('sha1', 'a'), ('is_exec', mode, False),
1489
                         ], 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.
1490
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1491
                         link_or_sha1)
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1492
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1493
                         state._dirblock_state)
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1494
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1495
                         entry[1])
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1496
        state.save()
1497
1498
        # However, if we move the clock forward so the file is considered
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1499
        # "stable", it should just cache the value.
1500
        state.adjust_time(+20)
1501
        link_or_sha1 = state.update_entry(entry, abspath='a',
1502
                                          stat_value=stat_value)
1503
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1504
                         link_or_sha1)
1505
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1506
                          ('sha1', 'a'), ('is_exec', mode, False),
1507
                          ('sha1', 'a'), ('is_exec', mode, False),
1508
                         ], state._log)
1509
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1510
                         entry[1])
1511
1512
        # Subsequent calls will just return the cached value
1513
        link_or_sha1 = state.update_entry(entry, abspath='a',
1514
                                          stat_value=stat_value)
1515
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1516
                         link_or_sha1)
1517
        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1518
                          ('sha1', 'a'), ('is_exec', mode, False),
1519
                          ('sha1', 'a'), ('is_exec', mode, False),
1520
                         ], state._log)
1521
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1522
                         entry[1])
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1523
1524
    def test_update_entry_symlink(self):
1525
        """Update entry should read symlinks."""
1526
        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
1527
            # PlatformDeficiency / TestSkipped
1528
            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.
1529
        state, entry = self.get_state_with_a()
1530
        state.save()
1531
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1532
                         state._dirblock_state)
1533
        os.symlink('target', 'a')
1534
1535
        state.adjust_time(-10) # Make the symlink look new
1536
        stat_value = os.lstat('a')
1537
        packed_stat = dirstate.pack_stat(stat_value)
1538
        link_or_sha1 = state.update_entry(entry, abspath='a',
1539
                                          stat_value=stat_value)
1540
        self.assertEqual('target', link_or_sha1)
1541
        self.assertEqual([('read_link', 'a', '')], state._log)
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1542
        # Dirblock is not updated (the link is too new)
1543
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1544
                         entry[1])
1545
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1546
                         state._dirblock_state)
1547
1548
        # Because the stat_value looks new, we should re-read the target
1549
        link_or_sha1 = state.update_entry(entry, abspath='a',
1550
                                          stat_value=stat_value)
1551
        self.assertEqual('target', link_or_sha1)
1552
        self.assertEqual([('read_link', 'a', ''),
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1553
                          ('read_link', '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.
1554
                         ], state._log)
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1555
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1556
                         entry[1])
2255.10.5 by John Arbash Meinel
Fix a small bug when we have a symlink that does not need to be re-read.
1557
        state.adjust_time(+20) # Skip into the future, all files look old
1558
        link_or_sha1 = state.update_entry(entry, abspath='a',
1559
                                          stat_value=stat_value)
1560
        self.assertEqual('target', link_or_sha1)
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1561
        # We need to re-read the link because only now can we cache it
1562
        self.assertEqual([('read_link', 'a', ''),
1563
                          ('read_link', 'a', ''),
1564
                          ('read_link', 'a', ''),
1565
                         ], state._log)
1566
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1567
                         entry[1])
1568
1569
        # Another call won't re-read the link
1570
        self.assertEqual([('read_link', 'a', ''),
1571
                          ('read_link', 'a', ''),
1572
                          ('read_link', 'a', ''),
1573
                         ], state._log)
1574
        link_or_sha1 = state.update_entry(entry, abspath='a',
1575
                                          stat_value=stat_value)
1576
        self.assertEqual('target', link_or_sha1)
1577
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1578
                         entry[1])
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1579
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1580
    def do_update_entry(self, state, entry, abspath):
1581
        stat_value = os.lstat(abspath)
1582
        return state.update_entry(entry, abspath, stat_value)
1583
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1584
    def test_update_entry_dir(self):
1585
        state, entry = self.get_state_with_a()
1586
        self.build_tree(['a/'])
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1587
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1588
2485.3.1 by John Arbash Meinel
Fix DirState handling of dir records.
1589
    def test_update_entry_dir_unchanged(self):
1590
        state, entry = self.get_state_with_a()
1591
        self.build_tree(['a/'])
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1592
        state.adjust_time(+20)
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1593
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
2485.3.1 by John Arbash Meinel
Fix DirState handling of dir records.
1594
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1595
                         state._dirblock_state)
1596
        state.save()
1597
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1598
                         state._dirblock_state)
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1599
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
2485.3.1 by John Arbash Meinel
Fix DirState handling of dir records.
1600
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1601
                         state._dirblock_state)
1602
1603
    def test_update_entry_file_unchanged(self):
1604
        state, entry = self.get_state_with_a()
1605
        self.build_tree(['a'])
1606
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1607
        state.adjust_time(+20)
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1608
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
2485.3.1 by John Arbash Meinel
Fix DirState handling of dir records.
1609
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1610
                         state._dirblock_state)
1611
        state.save()
1612
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1613
                         state._dirblock_state)
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1614
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
2485.3.1 by John Arbash Meinel
Fix DirState handling of dir records.
1615
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1616
                         state._dirblock_state)
1617
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1618
    def create_and_test_file(self, state, entry):
1619
        """Create a file at 'a' and verify the state finds it.
1620
1621
        The state should already be versioning *something* at 'a'. This makes
1622
        sure that state.update_entry recognizes it as a file.
1623
        """
1624
        self.build_tree(['a'])
1625
        stat_value = os.lstat('a')
1626
        packed_stat = dirstate.pack_stat(stat_value)
1627
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1628
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1629
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1630
                         link_or_sha1)
1631
        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1632
                         entry[1])
1633
        return packed_stat
1634
1635
    def create_and_test_dir(self, state, entry):
1636
        """Create a directory at 'a' and verify the state finds it.
1637
1638
        The state should already be versioning *something* at 'a'. This makes
1639
        sure that state.update_entry recognizes it as a directory.
1640
        """
1641
        self.build_tree(['a/'])
1642
        stat_value = os.lstat('a')
1643
        packed_stat = dirstate.pack_stat(stat_value)
1644
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1645
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1646
        self.assertIs(None, link_or_sha1)
1647
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1648
1649
        return packed_stat
1650
1651
    def create_and_test_symlink(self, state, entry):
1652
        """Create a symlink at 'a' and verify the state finds it.
1653
1654
        The state should already be versioning *something* at 'a'. This makes
1655
        sure that state.update_entry recognizes it as a symlink.
1656
1657
        This should not be called if this platform does not have symlink
1658
        support.
1659
        """
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1660
        # 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
1661
        os.symlink('path/to/foo', 'a')
1662
1663
        stat_value = os.lstat('a')
1664
        packed_stat = dirstate.pack_stat(stat_value)
1665
2485.3.3 by John Arbash Meinel
Avoid extra work in inner 'DirState.update_entry' code.
1666
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1667
        self.assertEqual('path/to/foo', link_or_sha1)
1668
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1669
                         entry[1])
1670
        return packed_stat
1671
1672
    def test_update_file_to_dir(self):
1673
        """If a file changes to a directory we return None for the sha.
1674
        We also update the inventory record.
1675
        """
1676
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1677
        # The file sha1 won't be cached unless the file is old
1678
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1679
        self.create_and_test_file(state, entry)
1680
        os.remove('a')
1681
        self.create_and_test_dir(state, entry)
1682
1683
    def test_update_file_to_symlink(self):
1684
        """File becomes a symlink"""
1685
        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
1686
            # PlatformDeficiency / TestSkipped
1687
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1688
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1689
        # The file sha1 won't be cached unless the file is old
1690
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1691
        self.create_and_test_file(state, entry)
1692
        os.remove('a')
1693
        self.create_and_test_symlink(state, entry)
1694
1695
    def test_update_dir_to_file(self):
1696
        """Directory becoming a file updates the entry."""
1697
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1698
        # The file sha1 won't be cached unless the file is old
1699
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1700
        self.create_and_test_dir(state, entry)
1701
        os.rmdir('a')
1702
        self.create_and_test_file(state, entry)
1703
1704
    def test_update_dir_to_symlink(self):
1705
        """Directory becomes a symlink"""
1706
        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
1707
            # PlatformDeficiency / TestSkipped
1708
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1709
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1710
        # The symlink target won't be cached if it isn't old
1711
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1712
        self.create_and_test_dir(state, entry)
1713
        os.rmdir('a')
1714
        self.create_and_test_symlink(state, entry)
1715
1716
    def test_update_symlink_to_file(self):
1717
        """Symlink becomes a file"""
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1718
        if not has_symlinks():
1719
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1720
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1721
        # The symlink and file info won't be cached unless old
1722
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1723
        self.create_and_test_symlink(state, entry)
1724
        os.remove('a')
1725
        self.create_and_test_file(state, entry)
1726
1727
    def test_update_symlink_to_dir(self):
1728
        """Symlink becomes a directory"""
2321.3.3 by Alexander Belchenko
test_dirstate: skip tests with symlinks on platforms that don't have symlinks support
1729
        if not has_symlinks():
1730
            raise TestSkipped("No symlink support")
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1731
        state, entry = self.get_state_with_a()
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1732
        # The symlink target won't be cached if it isn't old
1733
        state.adjust_time(+10)
2255.10.3 by John Arbash Meinel
(broken) Change get_sha1_for_entry into update_entry
1734
        self.create_and_test_symlink(state, entry)
1735
        os.remove('a')
1736
        self.create_and_test_dir(state, entry)
2255.10.2 by John Arbash Meinel
Update to dirstate locking.
1737
2255.10.7 by John Arbash Meinel
Some updates to how we handle the executable bit. In preparation for supporting Win32
1738
    def test__is_executable_win32(self):
1739
        state, entry = self.get_state_with_a()
1740
        self.build_tree(['a'])
1741
1742
        # Make sure we are using the win32 implementation of _is_executable
1743
        state._is_executable = state._is_executable_win32
1744
1745
        # The file on disk is not executable, but we are marking it as though
1746
        # it is. With _is_executable_win32 we ignore what is on disk.
1747
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1748
1749
        stat_value = os.lstat('a')
1750
        packed_stat = dirstate.pack_stat(stat_value)
1751
1752
        state.adjust_time(-10) # Make sure everything is new
1753
        state.update_entry(entry, abspath='a', stat_value=stat_value)
1754
1755
        # The row is updated, but the executable bit stays set.
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1756
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1757
                         entry[1])
1758
1759
        # Make the disk object look old enough to cache
1760
        state.adjust_time(+20)
2255.10.7 by John Arbash Meinel
Some updates to how we handle the executable bit. In preparation for supporting Win32
1761
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
2485.3.14 by John Arbash Meinel
Update the code so that symlinks aren't cached at incorrect times
1762
        state.update_entry(entry, abspath='a', stat_value=stat_value)
2255.10.7 by John Arbash Meinel
Some updates to how we handle the executable bit. In preparation for supporting Win32
1763
        self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1764
2255.10.1 by John Arbash Meinel
Update WorkingTree4 so that it doesn't use a HashCache,
1765
1766
class TestPackStat(TestCaseWithTransport):
1767
1768
    def assertPackStat(self, expected, stat_value):
1769
        """Check the packed and serialized form of a stat value."""
1770
        self.assertEqual(expected, dirstate.pack_stat(stat_value))
1771
1772
    def test_pack_stat_int(self):
1773
        st = _FakeStat(6859L, 1172758614, 1172758617, 777L, 6499538L, 0100644)
1774
        # Make sure that all parameters have an impact on the packed stat.
1775
        self.assertPackStat('AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
1776
        st.st_size = 7000L
1777
        #                ay0 => bWE
1778
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1779
        st.st_mtime = 1172758620
1780
        #                     4FZ => 4Fx
1781
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1782
        st.st_ctime = 1172758630
1783
        #                          uBZ => uBm
1784
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1785
        st.st_dev = 888L
1786
        #                                DCQ => DeA
1787
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
1788
        st.st_ino = 6499540L
1789
        #                                     LNI => LNQ
1790
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
1791
        st.st_mode = 0100744
1792
        #                                          IGk => IHk
1793
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
1794
1795
    def test_pack_stat_float(self):
1796
        """On some platforms mtime and ctime are floats.
1797
1798
        Make sure we don't get warnings or errors, and that we ignore changes <
1799
        1s
1800
        """
1801
        st = _FakeStat(7000L, 1172758614.0, 1172758617.0,
1802
                       777L, 6499538L, 0100644)
1803
        # These should all be the same as the integer counterparts
1804
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1805
        st.st_mtime = 1172758620.0
1806
        #                     FZF5 => FxF5
1807
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1808
        st.st_ctime = 1172758630.0
1809
        #                          uBZ => uBm
1810
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1811
        # fractional seconds are discarded, so no change from above
1812
        st.st_mtime = 1172758620.453
1813
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1814
        st.st_ctime = 1172758630.228
1815
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1816
1817
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
1818
class TestBisect(TestCaseWithDirState):
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1819
    """Test the ability to bisect into the disk format."""
1820
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1821
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1822
    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.
1823
        """Assert that bisecting for paths returns the right result.
1824
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1825
        :param expected_map: A map from key => entry value
1826
        :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.
1827
        :param state: The DirState object.
1828
        :param paths: A list of paths, these will automatically be split into
1829
                      (dir, name) tuples, and sorted according to how _bisect
1830
                      requires.
1831
        """
1832
        dir_names = sorted(osutils.split(p) for p in paths)
1833
        result = state._bisect(dir_names)
2255.2.126 by John Arbash Meinel
Switch the bisect code to support the fact that we can have
1834
        # For now, results are just returned in whatever order we read them.
1835
        # We could sort by (dir, name, file_id) or something like that, but in
1836
        # 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
1837
        # extra overhead if we can avoid it. So sort everything to make sure
1838
        # equality is true
1839
        assert len(map_keys) == len(dir_names)
1840
        expected = {}
1841
        for dir_name, keys in zip(dir_names, map_keys):
1842
            if keys is None:
1843
                # This should not be present in the output
1844
                continue
1845
            expected[dir_name] = sorted(expected_map[k] for k in keys)
1846
1847
        for dir_name in result:
1848
            result[dir_name].sort()
1849
1850
        self.assertEqual(expected, result)
1851
1852
    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.
1853
        """Assert that bisecting for dirbblocks returns the right result.
1854
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1855
        :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
1856
        :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.
1857
            Something like [['a', 'b', 'f'], ['b/c', 'b/d']]
1858
        :param state: The DirState object.
1859
        :param paths: A list of directories
1860
        """
1861
        result = state._bisect_dirblocks(paths)
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1862
        assert len(map_keys) == len(paths)
1863
1864
        expected = {}
1865
        for path, keys in zip(paths, map_keys):
1866
            if keys is None:
1867
                # This should not be present in the output
1868
                continue
1869
            expected[path] = sorted(expected_map[k] for k in keys)
1870
        for path in result:
1871
            result[path].sort()
1872
1873
        self.assertEqual(expected, result)
2255.2.130 by John Arbash Meinel
Add a very similar function which grabs everything for a particular directory block.
1874
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1875
    def assertBisectRecursive(self, expected_map, map_keys, state, paths):
1876
        """Assert the return value of a recursive bisection.
1877
1878
        :param expected_map: A map from key => entry value
1879
        :param map_keys: A list of paths we expect to be returned.
1880
            Something like ['a', 'b', 'f', 'b/d', 'b/d2']
1881
        :param state: The DirState object.
1882
        :param paths: A list of files and directories. It will be broken up
1883
            into (dir, name) pairs and sorted before calling _bisect_recursive.
1884
        """
1885
        expected = {}
1886
        for key in map_keys:
1887
            entry = expected_map[key]
1888
            dir_name_id, trees_info = entry
1889
            expected[dir_name_id] = trees_info
1890
1891
        dir_names = sorted(osutils.split(p) for p in paths)
1892
        result = state._bisect_recursive(dir_names)
1893
1894
        self.assertEqual(expected, result)
1895
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1896
    def test_bisect_each(self):
1897
        """Find a single record using bisect."""
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1898
        tree, state, expected = self.create_basic_dirstate()
2255.3.2 by John Arbash Meinel
(broken) some basic work on adding bisect functionality to dirstate.
1899
1900
        # 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
1901
        self.assertBisect(expected, [['']], state, [''])
1902
        self.assertBisect(expected, [['a']], state, ['a'])
1903
        self.assertBisect(expected, [['b']], state, ['b'])
1904
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1905
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1906
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1907
        self.assertBisect(expected, [['f']], state, ['f'])
2255.2.125 by John Arbash Meinel
Initial effort at adding a basic _bisect function to DirState.
1908
1909
    def test_bisect_multi(self):
1910
        """Bisect can be used to find multiple records at the same time."""
1911
        tree, state, expected = self.create_basic_dirstate()
1912
        # 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
1913
        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
1914
                          state, ['a', 'b', 'f'])
1915
        # ('', 'f') sorts before the others
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1916
        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
1917
                          state, ['b/d', 'b/d/e', 'f'])
1918
1919
    def test_bisect_one_page(self):
1920
        """Test bisect when there is only 1 page to read"""
1921
        tree, state, expected = self.create_basic_dirstate()
1922
        state._bisect_page_size = 5000
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1923
        self.assertBisect(expected,[['']], state, [''])
1924
        self.assertBisect(expected,[['a']], state, ['a'])
1925
        self.assertBisect(expected,[['b']], state, ['b'])
1926
        self.assertBisect(expected,[['b/c']], state, ['b/c'])
1927
        self.assertBisect(expected,[['b/d']], state, ['b/d'])
1928
        self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
1929
        self.assertBisect(expected,[['f']], state, ['f'])
1930
        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
1931
                          state, ['a', 'b', 'f'])
1932
        # ('', 'f') sorts before the others
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1933
        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
1934
                          state, ['b/d', 'b/d/e', 'f'])
1935
1936
    def test_bisect_duplicate_paths(self):
1937
        """When bisecting for a path, handle multiple entries."""
1938
        tree, state, expected = self.create_duplicated_dirstate()
1939
1940
        # 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
1941
        self.assertBisect(expected, [['']], state, [''])
1942
        self.assertBisect(expected, [['a', 'a2']], state, ['a'])
1943
        self.assertBisect(expected, [['b', 'b2']], state, ['b'])
1944
        self.assertBisect(expected, [['b/c', 'b/c2']], state, ['b/c'])
1945
        self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
1946
        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
1947
                          state, ['b/d/e'])
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1948
        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
1949
1950
    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.
1951
        """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
1952
        tree, state, expected = self.create_basic_dirstate()
1953
        state._bisect_page_size = 50
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1954
        self.assertBisect(expected, [None], state, ['b/e'])
1955
        self.assertBisect(expected, [['a']], state, ['a'])
1956
        self.assertBisect(expected, [['b']], state, ['b'])
1957
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1958
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1959
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1960
        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
1961
1962
    def test_bisect_missing(self):
1963
        """Test that bisect return None if it cannot find a path."""
1964
        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
1965
        self.assertBisect(expected, [None], state, ['foo'])
1966
        self.assertBisect(expected, [None], state, ['b/foo'])
1967
        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
1968
2255.2.131 by John Arbash Meinel
Change the return values for bisect functions so they just return
1969
        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
1970
                          state, ['a', 'foo', 'b/d'])
2255.2.127 by John Arbash Meinel
Expand the test suite to cover more cases.
1971
1972
    def test_bisect_rename(self):
1973
        """Check that we find a renamed row."""
1974
        tree, state, expected = self.create_renamed_dirstate()
1975
1976
        # 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
1977
        self.assertBisect(expected, [['a']], state, ['a'])
1978
        self.assertBisect(expected, [['b/g']], state, ['b/g'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
1979
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1980
        self.assertBisect(expected, [['h']], state, ['h'])
1981
1982
        # What about b/d/e? shouldn't that also get 2 directory entries?
1983
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1984
        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.
1985
1986
    def test_bisect_dirblocks(self):
1987
        tree, state, expected = self.create_duplicated_dirstate()
1988
        self.assertBisectDirBlocks(expected,
1989
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2']], state, [''])
1990
        self.assertBisectDirBlocks(expected,
1991
            [['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
1992
        self.assertBisectDirBlocks(expected,
1993
            [['b/d/e', 'b/d/e2']], state, ['b/d'])
1994
        self.assertBisectDirBlocks(expected,
1995
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2'],
1996
             ['b/c', 'b/c2', 'b/d', 'b/d2'],
1997
             ['b/d/e', 'b/d/e2'],
1998
            ], state, ['', 'b', 'b/d'])
1999
2000
    def test_bisect_dirblocks_missing(self):
2001
        tree, state, expected = self.create_basic_dirstate()
2002
        self.assertBisectDirBlocks(expected, [['b/d/e'], None],
2003
            state, ['b/d', 'b/e'])
2004
        # Files don't show up in this search
2005
        self.assertBisectDirBlocks(expected, [None], state, ['a'])
2006
        self.assertBisectDirBlocks(expected, [None], state, ['b/c'])
2007
        self.assertBisectDirBlocks(expected, [None], state, ['c'])
2008
        self.assertBisectDirBlocks(expected, [None], state, ['b/d/e'])
2009
        self.assertBisectDirBlocks(expected, [None], state, ['f'])
2255.2.132 by John Arbash Meinel
Implement _bisect_recursive, which uses multiple bisect calls to
2010
2011
    def test_bisect_recursive_each(self):
2012
        tree, state, expected = self.create_basic_dirstate()
2013
        self.assertBisectRecursive(expected, ['a'], state, ['a'])
2014
        self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
2015
        self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
2016
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2017
                                   state, ['b/d'])
2018
        self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
2019
                                   state, ['b'])
2020
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'f', 'b/c',
2021
                                              'b/d', 'b/d/e'],
2022
                                   state, [''])
2023
2024
    def test_bisect_recursive_multiple(self):
2025
        tree, state, expected = self.create_basic_dirstate()
2026
        self.assertBisectRecursive(expected, ['a', 'b/c'], state, ['a', 'b/c'])
2027
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2028
                                   state, ['b/d', 'b/d/e'])
2029
2030
    def test_bisect_recursive_missing(self):
2031
        tree, state, expected = self.create_basic_dirstate()
2032
        self.assertBisectRecursive(expected, [], state, ['d'])
2033
        self.assertBisectRecursive(expected, [], state, ['b/e'])
2034
        self.assertBisectRecursive(expected, [], state, ['g'])
2035
        self.assertBisectRecursive(expected, ['a'], state, ['a', 'g'])
2036
2037
    def test_bisect_recursive_renamed(self):
2038
        tree, state, expected = self.create_renamed_dirstate()
2039
2040
        # Looking for either renamed item should find the other
2041
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
2042
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
2043
        # Looking in the containing directory should find the rename target,
2044
        # and anything in a subdir of the renamed target.
2045
        self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
2046
                                              'b/d/e', 'b/g', 'h', 'h/e'],
2047
                                   state, ['b'])
2048
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2049
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2050
class TestBisectDirblock(TestCase):
2051
    """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,
2052
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2053
    bisect_dirblock is intended to work like bisect.bisect_left() except it
2054
    knows it is working on dirblocks and that dirblocks are sorted by ('path',
2055
    '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,
2056
    """
2057
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2058
    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,
2059
        """Assert that bisect_split works like bisect_left on the split paths.
2060
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2061
        :param dirblocks: A list of (path, [info]) pairs.
2062
        :param split_dirblocks: A list of ((split, path), [info]) pairs.
2063
        :param path: The path we are indexing.
2064
2065
        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,
2066
        """
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2067
        bisect_split_idx = dirstate.bisect_dirblock(dirblocks, path,
2068
                                                 *args, **kwargs)
2069
        split_dirblock = (path.split('/'), [])
2070
        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,
2071
                                             *args)
2072
        self.assertEqual(bisect_left_idx, bisect_split_idx,
2073
                         'bisect_split disagreed. %s != %s'
2074
                         ' for key %s'
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2075
                         % (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,
2076
                         )
2077
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2078
    def paths_to_dirblocks(self, paths):
2079
        """Convert a list of paths into dirblock form.
2080
2081
        Also, ensure that the paths are in proper sorted order.
2082
        """
2083
        dirblocks = [(path, []) for path in paths]
2084
        split_dirblocks = [(path.split('/'), []) for path in paths]
2085
        self.assertEqual(sorted(split_dirblocks), split_dirblocks)
2086
        return dirblocks, split_dirblocks
2087
2255.8.2 by John Arbash Meinel
Add a helper function, which allows us to store keys as plain paths,
2088
    def test_simple(self):
2089
        """In the simple case it works just like bisect_left"""
2090
        paths = ['', 'a', 'b', 'c', 'd']
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2091
        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,
2092
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2093
            self.assertBisect(dirblocks, split_dirblocks, path)
2094
        self.assertBisect(dirblocks, split_dirblocks, '_')
2095
        self.assertBisect(dirblocks, split_dirblocks, 'aa')
2096
        self.assertBisect(dirblocks, split_dirblocks, 'bb')
2097
        self.assertBisect(dirblocks, split_dirblocks, 'cc')
2098
        self.assertBisect(dirblocks, split_dirblocks, 'dd')
2099
        self.assertBisect(dirblocks, split_dirblocks, 'a/a')
2100
        self.assertBisect(dirblocks, split_dirblocks, 'b/b')
2101
        self.assertBisect(dirblocks, split_dirblocks, 'c/c')
2102
        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,
2103
2104
    def test_involved(self):
2105
        """This is where bisect_left diverges slightly."""
2106
        paths = ['', 'a',
2107
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2108
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2109
                 'a-a', 'a-z',
2110
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2111
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2112
                 'z-a', 'z-z',
2113
                ]
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2114
        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,
2115
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2116
            self.assertBisect(dirblocks, split_dirblocks, path)
2255.8.3 by John Arbash Meinel
Add the ability to cache the split output
2117
2118
    def test_involved_cached(self):
2119
        """This is where bisect_left diverges slightly."""
2120
        paths = ['', 'a',
2121
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2122
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2123
                 'a-a', 'a-z',
2124
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2125
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2126
                 'z-a', 'z-z',
2127
                ]
2128
        cache = {}
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2129
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2255.8.3 by John Arbash Meinel
Add the ability to cache the split output
2130
        for path in paths:
2255.8.4 by John Arbash Meinel
Rather than using split hunks, implement a bisect_dirblocks
2131
            self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
2132
2323.5.4 by Martin Pool
Move some dirstate test setup methods into the base class
2133
2134
class TestDirstateValidation(TestCaseWithDirState):
2135
2136
    def test_validate_correct_dirstate(self):
2137
        state = self.create_complex_dirstate()
2138
        state._validate()
2139
        state.unlock()
2140
        # and make sure we can also validate with a read lock
2141
        state.lock_read()
2142
        try:
2143
            state._validate()
2144
        finally:
2145
            state.unlock()
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2146
2147
    def test_dirblock_not_sorted(self):
2148
        tree, state, expected = self.create_renamed_dirstate()
2149
        state._read_dirblocks_if_needed()
2150
        last_dirblock = state._dirblocks[-1]
2151
        # we're appending to the dirblock, but this name comes before some of
2152
        # the existing names; that's wrong
2153
        last_dirblock[1].append(
2154
            (('h', 'aaaa', 'a-id'),
2155
             [('a', '', 0, False, ''),
2156
              ('a', '', 0, False, '')]))
2157
        e = self.assertRaises(AssertionError,
2158
            state._validate)
2159
        self.assertContainsRe(str(e), 'not sorted')
2160
2161
    def test_dirblock_name_mismatch(self):
2162
        tree, state, expected = self.create_renamed_dirstate()
2163
        state._read_dirblocks_if_needed()
2164
        last_dirblock = state._dirblocks[-1]
2165
        # add an entry with the wrong directory name
2166
        last_dirblock[1].append(
2167
            (('', 'z', 'a-id'),
2168
             [('a', '', 0, False, ''),
2169
              ('a', '', 0, False, '')]))
2170
        e = self.assertRaises(AssertionError,
2171
            state._validate)
2172
        self.assertContainsRe(str(e),
2173
            "doesn't match directory name")
2174
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2175
    def test_dirblock_missing_rename(self):
2176
        tree, state, expected = self.create_renamed_dirstate()
2177
        state._read_dirblocks_if_needed()
2178
        last_dirblock = state._dirblocks[-1]
2323.5.6 by Martin Pool
Add some tests and better messages for DirState._validate
2179
        # make another entry for a-id, without a correct 'r' pointer to
2180
        # the real occurrence in the working tree
2323.5.7 by Martin Pool
Better DirState._validate and tests for it.
2181
        last_dirblock[1].append(
2182
            (('h', 'z', 'a-id'),
2183
             [('a', '', 0, False, ''),
2184
              ('a', '', 0, False, '')]))
2185
        e = self.assertRaises(AssertionError,
2186
            state._validate)
2187
        self.assertContainsRe(str(e),
2188
            'file a-id is absent in row')