~bzr-pqm/bzr/bzr.dev

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