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