/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to brzlib/tests/test_dirstate.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os
20
20
import tempfile
21
21
 
22
 
from .. import (
 
22
from brzlib import (
23
23
    controldir,
 
24
    dirstate,
24
25
    errors,
 
26
    inventory,
25
27
    memorytree,
26
28
    osutils,
27
29
    revision as _mod_revision,
28
30
    revisiontree,
29
31
    tests,
30
 
    )
31
 
from ..bzr import (
32
 
    dirstate,
33
 
    inventory,
34
 
    inventorytree,
35
32
    workingtree_4,
36
33
    )
37
 
from . import (
 
34
from brzlib.tests import (
38
35
    features,
39
36
    test_osutils,
40
37
    )
41
 
from .scenarios import load_tests_apply_scenarios
 
38
from brzlib.tests.scenarios import load_tests_apply_scenarios
42
39
 
43
40
 
44
41
# TODO:
54
51
# set_path_id  setting id when state is in memory modified
55
52
 
56
53
 
57
 
class TestErrors(tests.TestCase):
58
 
 
59
 
    def test_dirstate_corrupt(self):
60
 
        error = dirstate.DirstateCorrupt('.bzr/checkout/dirstate',
61
 
                                         'trailing garbage: "x"')
62
 
        self.assertEqualDiff("The dirstate file (.bzr/checkout/dirstate)"
63
 
                             " appears to be corrupt: trailing garbage: \"x\"",
64
 
                             str(error))
65
 
 
66
 
 
67
54
load_tests = load_tests_apply_scenarios
68
55
 
69
56
 
74
61
 
75
62
    # Set by load_tests
76
63
    _dir_reader_class = None
77
 
    _native_to_unicode = None  # Not used yet
 
64
    _native_to_unicode = None # Not used yet
78
65
 
79
66
    def setUp(self):
80
67
        super(TestCaseWithDirState, self).setUp()
88
75
 
89
76
    def create_dirstate_with_root(self):
90
77
        """Return a write-locked state with a single root entry."""
91
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
92
 
        root_entry_direntry = (b'', b'', b'a-root-value'), [
93
 
            (b'd', b'', 0, False, packed_stat),
 
78
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
79
        root_entry_direntry = ('', '', 'a-root-value'), [
 
80
            ('d', '', 0, False, packed_stat),
94
81
            ]
95
82
        dirblocks = []
96
 
        dirblocks.append((b'', [root_entry_direntry]))
97
 
        dirblocks.append((b'', []))
 
83
        dirblocks.append(('', [root_entry_direntry]))
 
84
        dirblocks.append(('', []))
98
85
        state = self.create_empty_dirstate()
99
86
        try:
100
87
            state._set_data([], dirblocks)
106
93
 
107
94
    def create_dirstate_with_root_and_subdir(self):
108
95
        """Return a locked DirState with a root and a subdir"""
109
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
110
 
        subdir_entry = (b'', b'subdir', b'subdir-id'), [
111
 
            (b'd', b'', 0, False, packed_stat),
 
96
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
97
        subdir_entry = ('', 'subdir', 'subdir-id'), [
 
98
            ('d', '', 0, False, packed_stat),
112
99
            ]
113
100
        state = self.create_dirstate_with_root()
114
101
        try:
137
124
 
138
125
        :return: The dirstate, still write-locked.
139
126
        """
140
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
141
 
        null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
142
 
        root_entry = (b'', b'', b'a-root-value'), [
143
 
            (b'd', b'', 0, False, packed_stat),
144
 
            ]
145
 
        a_entry = (b'', b'a', b'a-dir'), [
146
 
            (b'd', b'', 0, False, packed_stat),
147
 
            ]
148
 
        b_entry = (b'', b'b', b'b-dir'), [
149
 
            (b'd', b'', 0, False, packed_stat),
150
 
            ]
151
 
        c_entry = (b'', b'c', b'c-file'), [
152
 
            (b'f', null_sha, 10, False, packed_stat),
153
 
            ]
154
 
        d_entry = (b'', b'd', b'd-file'), [
155
 
            (b'f', null_sha, 20, False, packed_stat),
156
 
            ]
157
 
        e_entry = (b'a', b'e', b'e-dir'), [
158
 
            (b'd', b'', 0, False, packed_stat),
159
 
            ]
160
 
        f_entry = (b'a', b'f', b'f-file'), [
161
 
            (b'f', null_sha, 30, False, packed_stat),
162
 
            ]
163
 
        g_entry = (b'b', b'g', b'g-file'), [
164
 
            (b'f', null_sha, 30, False, packed_stat),
165
 
            ]
166
 
        h_entry = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file'), [
167
 
            (b'f', null_sha, 40, False, packed_stat),
 
127
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
128
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 
129
        root_entry = ('', '', 'a-root-value'), [
 
130
            ('d', '', 0, False, packed_stat),
 
131
            ]
 
132
        a_entry = ('', 'a', 'a-dir'), [
 
133
            ('d', '', 0, False, packed_stat),
 
134
            ]
 
135
        b_entry = ('', 'b', 'b-dir'), [
 
136
            ('d', '', 0, False, packed_stat),
 
137
            ]
 
138
        c_entry = ('', 'c', 'c-file'), [
 
139
            ('f', null_sha, 10, False, packed_stat),
 
140
            ]
 
141
        d_entry = ('', 'd', 'd-file'), [
 
142
            ('f', null_sha, 20, False, packed_stat),
 
143
            ]
 
144
        e_entry = ('a', 'e', 'e-dir'), [
 
145
            ('d', '', 0, False, packed_stat),
 
146
            ]
 
147
        f_entry = ('a', 'f', 'f-file'), [
 
148
            ('f', null_sha, 30, False, packed_stat),
 
149
            ]
 
150
        g_entry = ('b', 'g', 'g-file'), [
 
151
            ('f', null_sha, 30, False, packed_stat),
 
152
            ]
 
153
        h_entry = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file'), [
 
154
            ('f', null_sha, 40, False, packed_stat),
168
155
            ]
169
156
        dirblocks = []
170
 
        dirblocks.append((b'', [root_entry]))
171
 
        dirblocks.append((b'', [a_entry, b_entry, c_entry, d_entry]))
172
 
        dirblocks.append((b'a', [e_entry, f_entry]))
173
 
        dirblocks.append((b'b', [g_entry, h_entry]))
 
157
        dirblocks.append(('', [root_entry]))
 
158
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
 
159
        dirblocks.append(('a', [e_entry, f_entry]))
 
160
        dirblocks.append(('b', [g_entry, h_entry]))
174
161
        state = dirstate.DirState.initialize('dirstate')
175
162
        state._validate()
176
163
        try:
196
183
        # some operation to get here.
197
184
        self.assertTrue(state._lock_token is not None)
198
185
        try:
199
 
            self.assertEqual(expected_result[0], state.get_parent_ids())
 
186
            self.assertEqual(expected_result[0],  state.get_parent_ids())
200
187
            # there should be no ghosts in this tree.
201
188
            self.assertEqual([], state.get_ghosts())
202
189
            # there should be one fileid in this tree - the root of the tree.
225
212
        """
226
213
        tree = self.make_branch_and_tree('tree')
227
214
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'b-c', 'f']
228
 
        file_ids = [b'a-id', b'b-id', b'c-id',
229
 
                    b'd-id', b'e-id', b'b-c-id', b'f-id']
 
215
        file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'b-c-id', 'f-id']
230
216
        self.build_tree(['tree/' + p for p in paths])
231
 
        tree.set_root_id(b'TREE_ROOT')
 
217
        tree.set_root_id('TREE_ROOT')
232
218
        tree.add([p.rstrip('/') for p in paths], file_ids)
233
 
        tree.commit('initial', rev_id=b'rev-1')
234
 
        revision_id = b'rev-1'
 
219
        tree.commit('initial', rev_id='rev-1')
 
220
        revision_id = 'rev-1'
235
221
        # a_packed_stat = dirstate.pack_stat(os.stat('tree/a'))
236
222
        t = self.get_transport('tree')
237
223
        a_text = t.get_bytes('a')
256
242
        f_len = len(f_text)
257
243
        null_stat = dirstate.DirState.NULLSTAT
258
244
        expected = {
259
 
            b'': ((b'', b'', b'TREE_ROOT'), [
260
 
                  (b'd', b'', 0, False, null_stat),
261
 
                  (b'd', b'', 0, False, revision_id),
262
 
                  ]),
263
 
            b'a': ((b'', b'a', b'a-id'), [
264
 
                   (b'f', b'', 0, False, null_stat),
265
 
                   (b'f', a_sha, a_len, False, revision_id),
266
 
                   ]),
267
 
            b'b': ((b'', b'b', b'b-id'), [
268
 
                  (b'd', b'', 0, False, null_stat),
269
 
                  (b'd', b'', 0, False, revision_id),
270
 
                ]),
271
 
            b'b/c': ((b'b', b'c', b'c-id'), [
272
 
                    (b'f', b'', 0, False, null_stat),
273
 
                    (b'f', c_sha, c_len, False, revision_id),
274
 
                ]),
275
 
            b'b/d': ((b'b', b'd', b'd-id'), [
276
 
                    (b'd', b'', 0, False, null_stat),
277
 
                    (b'd', b'', 0, False, revision_id),
278
 
                ]),
279
 
            b'b/d/e': ((b'b/d', b'e', b'e-id'), [
280
 
                      (b'f', b'', 0, False, null_stat),
281
 
                      (b'f', e_sha, e_len, False, revision_id),
282
 
                ]),
283
 
            b'b-c': ((b'', b'b-c', b'b-c-id'), [
284
 
                (b'f', b'', 0, False, null_stat),
285
 
                (b'f', b_c_sha, b_c_len, False, revision_id),
286
 
                ]),
287
 
            b'f': ((b'', b'f', b'f-id'), [
288
 
                (b'f', b'', 0, False, null_stat),
289
 
                (b'f', f_sha, f_len, False, revision_id),
290
 
                ]),
 
245
            '':(('', '', 'TREE_ROOT'), [
 
246
                  ('d', '', 0, False, null_stat),
 
247
                  ('d', '', 0, False, revision_id),
 
248
                ]),
 
249
            'a':(('', 'a', 'a-id'), [
 
250
                   ('f', '', 0, False, null_stat),
 
251
                   ('f', a_sha, a_len, False, revision_id),
 
252
                 ]),
 
253
            'b':(('', 'b', 'b-id'), [
 
254
                  ('d', '', 0, False, null_stat),
 
255
                  ('d', '', 0, False, revision_id),
 
256
                 ]),
 
257
            'b/c':(('b', 'c', 'c-id'), [
 
258
                    ('f', '', 0, False, null_stat),
 
259
                    ('f', c_sha, c_len, False, revision_id),
 
260
                   ]),
 
261
            'b/d':(('b', 'd', 'd-id'), [
 
262
                    ('d', '', 0, False, null_stat),
 
263
                    ('d', '', 0, False, revision_id),
 
264
                   ]),
 
265
            'b/d/e':(('b/d', 'e', 'e-id'), [
 
266
                      ('f', '', 0, False, null_stat),
 
267
                      ('f', e_sha, e_len, False, revision_id),
 
268
                     ]),
 
269
            'b-c':(('', 'b-c', 'b-c-id'), [
 
270
                      ('f', '', 0, False, null_stat),
 
271
                      ('f', b_c_sha, b_c_len, False, revision_id),
 
272
                     ]),
 
273
            'f':(('', 'f', 'f-id'), [
 
274
                  ('f', '', 0, False, null_stat),
 
275
                  ('f', f_sha, f_len, False, revision_id),
 
276
                 ]),
291
277
        }
292
278
        state = dirstate.DirState.from_tree(tree, 'dirstate')
293
279
        try:
316
302
        tree, state, expected = self.create_basic_dirstate()
317
303
        # Now we will just remove and add every file so we get an extra entry
318
304
        # per entry. Unversion in reverse order so we handle subdirs
319
 
        tree.unversion(['f', 'b-c', 'b/d/e', 'b/d', 'b/c', 'b', 'a'])
 
305
        tree.unversion(['f-id', 'b-c-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
320
306
        tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f'],
321
 
                 [b'a-id2', b'b-id2', b'c-id2', b'd-id2', b'e-id2', b'b-c-id2', b'f-id2'])
 
307
                 ['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'b-c-id2', 'f-id2'])
322
308
 
323
309
        # Update the expected dictionary.
324
 
        for path in [b'a', b'b', b'b/c', b'b/d', b'b/d/e', b'b-c', b'f']:
 
310
        for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f']:
325
311
            orig = expected[path]
326
 
            path2 = path + b'2'
 
312
            path2 = path + '2'
327
313
            # This record was deleted in the current tree
328
314
            expected[path] = (orig[0], [dirstate.DirState.NULL_PARENT_DETAILS,
329
315
                                        orig[1][1]])
330
 
            new_key = (orig[0][0], orig[0][1], orig[0][2] + b'2')
 
316
            new_key = (orig[0][0], orig[0][1], orig[0][2]+'2')
331
317
            # And didn't exist in the basis tree
332
318
            expected[path2] = (new_key, [orig[1][0],
333
319
                                         dirstate.DirState.NULL_PARENT_DETAILS])
358
344
        # And a directory
359
345
        tree.rename_one('b/d', 'h')
360
346
 
361
 
        old_a = expected[b'a']
362
 
        expected[b'a'] = (
363
 
            old_a[0], [(b'r', b'b/g', 0, False, b''), old_a[1][1]])
364
 
        expected[b'b/g'] = ((b'b', b'g', b'a-id'), [old_a[1][0],
365
 
                                                    (b'r', b'a', 0, False, b'')])
366
 
        old_d = expected[b'b/d']
367
 
        expected[b'b/d'] = (old_d[0],
368
 
                            [(b'r', b'h', 0, False, b''), old_d[1][1]])
369
 
        expected[b'h'] = ((b'', b'h', b'd-id'), [old_d[1][0],
370
 
                                                 (b'r', b'b/d', 0, False, b'')])
 
347
        old_a = expected['a']
 
348
        expected['a'] = (old_a[0], [('r', 'b/g', 0, False, ''), old_a[1][1]])
 
349
        expected['b/g'] = (('b', 'g', 'a-id'), [old_a[1][0],
 
350
                                                ('r', 'a', 0, False, '')])
 
351
        old_d = expected['b/d']
 
352
        expected['b/d'] = (old_d[0], [('r', 'h', 0, False, ''), old_d[1][1]])
 
353
        expected['h'] = (('', 'h', 'd-id'), [old_d[1][0],
 
354
                                             ('r', 'b/d', 0, False, '')])
371
355
 
372
 
        old_e = expected[b'b/d/e']
373
 
        expected[b'b/d/e'] = (old_e[0], [(b'r', b'h/e', 0, False, b''),
374
 
                                         old_e[1][1]])
375
 
        expected[b'h/e'] = ((b'h', b'e', b'e-id'), [old_e[1][0],
376
 
                                                    (b'r', b'b/d/e', 0, False, b'')])
 
356
        old_e = expected['b/d/e']
 
357
        expected['b/d/e'] = (old_e[0], [('r', 'h/e', 0, False, ''),
 
358
                             old_e[1][1]])
 
359
        expected['h/e'] = (('h', 'e', 'e-id'), [old_e[1][0],
 
360
                                                ('r', 'b/d/e', 0, False, '')])
377
361
 
378
362
        state.unlock()
379
363
        try:
394
378
        # There are no files on disk and no parents
395
379
        tree = self.make_branch_and_tree('tree')
396
380
        expected_result = ([], [
397
 
            ((b'', b'', tree.path2id('')),  # common details
398
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
399
 
              ])])
 
381
            (('', '', tree.get_root_id()), # common details
 
382
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
383
             ])])
400
384
        state = dirstate.DirState.from_tree(tree, 'dirstate')
401
385
        state._validate()
402
386
        self.check_state_with_reopen(expected_result, state)
404
388
    def test_1_parents_empty_to_dirstate(self):
405
389
        # create a parent by doing a commit
406
390
        tree = self.make_branch_and_tree('tree')
407
 
        rev_id = tree.commit('first post')
 
391
        rev_id = tree.commit('first post').encode('utf8')
408
392
        root_stat_pack = dirstate.pack_stat(os.stat(tree.basedir))
409
393
        expected_result = ([rev_id], [
410
 
            ((b'', b'', tree.path2id('')),  # common details
411
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
412
 
              (b'd', b'', 0, False, rev_id),  # first parent details
413
 
              ])])
 
394
            (('', '', tree.get_root_id()), # common details
 
395
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
396
              ('d', '', 0, False, rev_id), # first parent details
 
397
             ])])
414
398
        state = dirstate.DirState.from_tree(tree, 'dirstate')
415
399
        self.check_state_with_reopen(expected_result, state)
416
400
        state.lock_read()
423
407
        # create a parent by doing a commit
424
408
        tree = self.make_branch_and_tree('tree')
425
409
        rev_id = tree.commit('first post')
426
 
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
 
410
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
427
411
        rev_id2 = tree2.commit('second post', allow_pointless=True)
428
412
        tree.merge_from_branch(tree2.branch)
429
413
        expected_result = ([rev_id, rev_id2], [
430
 
            ((b'', b'', tree.path2id('')),  # common details
431
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
432
 
              (b'd', b'', 0, False, rev_id),  # first parent details
433
 
              (b'd', b'', 0, False, rev_id),  # second parent details
434
 
              ])])
 
414
            (('', '', tree.get_root_id()), # common details
 
415
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
416
              ('d', '', 0, False, rev_id), # first parent details
 
417
              ('d', '', 0, False, rev_id), # second parent details
 
418
             ])])
435
419
        state = dirstate.DirState.from_tree(tree, 'dirstate')
436
420
        self.check_state_with_reopen(expected_result, state)
437
421
        state.lock_read()
446
430
        tree = self.make_branch_and_tree('tree')
447
431
        self.build_tree(['tree/unknown'])
448
432
        expected_result = ([], [
449
 
            ((b'', b'', tree.path2id('')),  # common details
450
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
451
 
              ])])
 
433
            (('', '', tree.get_root_id()), # common details
 
434
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
435
             ])])
452
436
        state = dirstate.DirState.from_tree(tree, 'dirstate')
453
437
        self.check_state_with_reopen(expected_result, state)
454
438
 
455
439
    def get_tree_with_a_file(self):
456
440
        tree = self.make_branch_and_tree('tree')
457
441
        self.build_tree(['tree/a file'])
458
 
        tree.add('a file', b'a-file-id')
 
442
        tree.add('a file', 'a-file-id')
459
443
        return tree
460
444
 
461
445
    def test_non_empty_no_parents_to_dirstate(self):
463
447
        # There are files on disk and no parents
464
448
        tree = self.get_tree_with_a_file()
465
449
        expected_result = ([], [
466
 
            ((b'', b'', tree.path2id('')),  # common details
467
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
468
 
              ]),
469
 
            ((b'', b'a file', b'a-file-id'),  # common
470
 
             [(b'f', b'', 0, False, dirstate.DirState.NULLSTAT),  # current
471
 
              ]),
 
450
            (('', '', tree.get_root_id()), # common details
 
451
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
452
             ]),
 
453
            (('', 'a file', 'a-file-id'), # common
 
454
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
455
             ]),
472
456
            ])
473
457
        state = dirstate.DirState.from_tree(tree, 'dirstate')
474
458
        self.check_state_with_reopen(expected_result, state)
476
460
    def test_1_parents_not_empty_to_dirstate(self):
477
461
        # create a parent by doing a commit
478
462
        tree = self.get_tree_with_a_file()
479
 
        rev_id = tree.commit('first post')
 
463
        rev_id = tree.commit('first post').encode('utf8')
480
464
        # change the current content to be different this will alter stat, sha
481
465
        # and length:
482
 
        self.build_tree_contents([('tree/a file', b'new content\n')])
 
466
        self.build_tree_contents([('tree/a file', 'new content\n')])
483
467
        expected_result = ([rev_id], [
484
 
            ((b'', b'', tree.path2id('')),  # common details
485
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
486
 
              (b'd', b'', 0, False, rev_id),  # first parent details
487
 
              ]),
488
 
            ((b'', b'a file', b'a-file-id'),  # common
489
 
             [(b'f', b'', 0, False, dirstate.DirState.NULLSTAT),  # current
490
 
              (b'f', b'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
491
 
               rev_id),  # first parent
492
 
              ]),
 
468
            (('', '', tree.get_root_id()), # common details
 
469
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
470
              ('d', '', 0, False, rev_id), # first parent details
 
471
             ]),
 
472
            (('', 'a file', 'a-file-id'), # common
 
473
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
474
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
 
475
               rev_id), # first parent
 
476
             ]),
493
477
            ])
494
478
        state = dirstate.DirState.from_tree(tree, 'dirstate')
495
479
        self.check_state_with_reopen(expected_result, state)
497
481
    def test_2_parents_not_empty_to_dirstate(self):
498
482
        # create a parent by doing a commit
499
483
        tree = self.get_tree_with_a_file()
500
 
        rev_id = tree.commit('first post')
501
 
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
 
484
        rev_id = tree.commit('first post').encode('utf8')
 
485
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
502
486
        # change the current content to be different this will alter stat, sha
503
487
        # and length:
504
 
        self.build_tree_contents([('tree2/a file', b'merge content\n')])
505
 
        rev_id2 = tree2.commit('second post')
 
488
        self.build_tree_contents([('tree2/a file', 'merge content\n')])
 
489
        rev_id2 = tree2.commit('second post').encode('utf8')
506
490
        tree.merge_from_branch(tree2.branch)
507
491
        # change the current content to be different this will alter stat, sha
508
492
        # and length again, giving us three distinct values:
509
 
        self.build_tree_contents([('tree/a file', b'new content\n')])
 
493
        self.build_tree_contents([('tree/a file', 'new content\n')])
510
494
        expected_result = ([rev_id, rev_id2], [
511
 
            ((b'', b'', tree.path2id('')),  # common details
512
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
513
 
              (b'd', b'', 0, False, rev_id),  # first parent details
514
 
              (b'd', b'', 0, False, rev_id),  # second parent details
515
 
              ]),
516
 
            ((b'', b'a file', b'a-file-id'),  # common
517
 
             [(b'f', b'', 0, False, dirstate.DirState.NULLSTAT),  # current
518
 
              (b'f', b'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
519
 
               rev_id),  # first parent
520
 
              (b'f', b'314d796174c9412647c3ce07dfb5d36a94e72958', 14, False,
521
 
               rev_id2),  # second parent
522
 
              ]),
 
495
            (('', '', tree.get_root_id()), # common details
 
496
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
497
              ('d', '', 0, False, rev_id), # first parent details
 
498
              ('d', '', 0, False, rev_id), # second parent details
 
499
             ]),
 
500
            (('', 'a file', 'a-file-id'), # common
 
501
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
 
502
              ('f', 'c3ed76e4bfd45ff1763ca206055bca8e9fc28aa8', 24, False,
 
503
               rev_id), # first parent
 
504
              ('f', '314d796174c9412647c3ce07dfb5d36a94e72958', 14, False,
 
505
               rev_id2), # second parent
 
506
             ]),
523
507
            ])
524
508
        state = dirstate.DirState.from_tree(tree, 'dirstate')
525
509
        self.check_state_with_reopen(expected_result, state)
532
516
        parents = []
533
517
        for i in range(7):
534
518
            tree = self.make_branch_and_tree('tree%d' % i)
535
 
            self.build_tree(['tree%d/name' % i, ])
536
 
            tree.add(['name'], [b'file-id%d' % i])
537
 
            revision_id = b'revid-%d' % i
 
519
            self.build_tree(['tree%d/name' % i,])
 
520
            tree.add(['name'], ['file-id%d' % i])
 
521
            revision_id = 'revid-%d' % i
538
522
            tree.commit('message', rev_id=revision_id)
539
523
            parents.append((revision_id,
540
 
                            tree.branch.repository.revision_tree(revision_id)))
 
524
                tree.branch.repository.revision_tree(revision_id)))
541
525
        # now fold these trees into a dirstate
542
526
        state = dirstate.DirState.initialize('dirstate')
543
527
        try:
552
536
    def create_updated_dirstate(self):
553
537
        self.build_tree(['a-file'])
554
538
        tree = self.make_branch_and_tree('.')
555
 
        tree.add(['a-file'], [b'a-id'])
 
539
        tree.add(['a-file'], ['a-id'])
556
540
        tree.commit('add a-file')
557
541
        # Save and unlock the state, re-open it in readonly mode
558
542
        state = dirstate.DirState.from_tree(tree, 'dirstate')
569
553
        # write to disk.
570
554
        lines = state.get_lines()
571
555
        state.unlock()
572
 
        self.build_tree_contents([('dirstate', b''.join(lines))])
 
556
        self.build_tree_contents([('dirstate', ''.join(lines))])
573
557
        # get a state object
574
558
        # no parents, default tree content
575
559
        expected_result = ([], [
576
 
            ((b'', b'', tree.path2id('')),  # common details
 
560
            (('', '', tree.get_root_id()), # common details
577
561
             # current tree details, but new from_tree skips statting, it
578
562
             # uses set_state_from_inventory, and thus depends on the
579
563
             # inventory state.
580
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),
581
 
              ])
 
564
             [('d', '', 0, False, dirstate.DirState.NULLSTAT),
 
565
             ])
582
566
            ])
583
567
        state = dirstate.DirState.on_file('dirstate')
584
 
        state.lock_write()  # check_state_with_reopen will save() and unlock it
 
568
        state.lock_write() # check_state_with_reopen will save() and unlock it
585
569
        self.check_state_with_reopen(expected_result, state)
586
570
 
587
571
    def test_can_save_clean_on_file(self):
598
582
    def test_can_save_in_read_lock(self):
599
583
        state = self.create_updated_dirstate()
600
584
        try:
601
 
            entry = state._get_entry(0, path_utf8=b'a-file')
 
585
            entry = state._get_entry(0, path_utf8='a-file')
602
586
            # The current size should be 0 (default)
603
587
            self.assertEqual(0, entry[1][0][2])
604
588
            # We should have a real entry.
609
593
            st = os.lstat('a-file')
610
594
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
611
595
            # We updated the current sha1sum because the file is cacheable
612
 
            self.assertEqual(b'ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
596
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
613
597
                             sha1sum)
614
598
 
615
599
            # The dirblock has been updated
628
612
        state = dirstate.DirState.on_file('dirstate')
629
613
        state.lock_read()
630
614
        try:
631
 
            entry = state._get_entry(0, path_utf8=b'a-file')
 
615
            entry = state._get_entry(0, path_utf8='a-file')
632
616
            self.assertEqual(st.st_size, entry[1][0][2])
633
617
        finally:
634
618
            state.unlock()
637
621
        """If dirstate is locked, save will fail without complaining."""
638
622
        state = self.create_updated_dirstate()
639
623
        try:
640
 
            entry = state._get_entry(0, path_utf8=b'a-file')
 
624
            entry = state._get_entry(0, path_utf8='a-file')
641
625
            # No cached sha1 yet.
642
 
            self.assertEqual(b'', entry[1][0][1])
 
626
            self.assertEqual('', entry[1][0][1])
643
627
            # Set the cutoff-time into the future, so things look cacheable
644
628
            state._sha_cutoff_time()
645
629
            state._cutoff_time += 10.0
646
630
            st = os.lstat('a-file')
647
631
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
648
 
            self.assertEqual(b'ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
632
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
649
633
                             sha1sum)
650
634
            self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
651
635
                             state._dirblock_state)
674
658
        state = dirstate.DirState.on_file('dirstate')
675
659
        state.lock_read()
676
660
        try:
677
 
            entry = state._get_entry(0, path_utf8=b'a-file')
678
 
            self.assertEqual(b'', entry[1][0][1])
 
661
            entry = state._get_entry(0, path_utf8='a-file')
 
662
            self.assertEqual('', entry[1][0][1])
679
663
        finally:
680
664
            state.unlock()
681
665
 
684
668
        state = dirstate.DirState.initialize('dirstate')
685
669
        try:
686
670
            # No stat and no sha1 sum.
687
 
            state.add('a-file', b'a-file-id', 'file', None, b'')
 
671
            state.add('a-file', 'a-file-id', 'file', None, '')
688
672
            state.save()
689
673
        finally:
690
674
            state.unlock()
691
675
 
692
676
        # The dirstate should include TREE_ROOT and 'a-file' and nothing else
693
677
        expected_blocks = [
694
 
            (b'', [((b'', b'', b'TREE_ROOT'),
695
 
                    [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT)])]),
696
 
            (b'', [((b'', b'a-file', b'a-file-id'),
697
 
                    [(b'f', b'', 0, False, dirstate.DirState.NULLSTAT)])]),
 
678
            ('', [(('', '', 'TREE_ROOT'),
 
679
                   [('d', '', 0, False, dirstate.DirState.NULLSTAT)])]),
 
680
            ('', [(('', 'a-file', 'a-file-id'),
 
681
                   [('f', '', 0, False, dirstate.DirState.NULLSTAT)])]),
698
682
        ]
699
683
 
700
684
        state = dirstate.DirState.on_file('dirstate')
704
688
            self.assertEqual(expected_blocks, state._dirblocks)
705
689
 
706
690
            # Now modify the state, but mark it as inconsistent
707
 
            state.add('a-dir', b'a-dir-id', 'directory', None, b'')
 
691
            state.add('a-dir', 'a-dir-id', 'directory', None, '')
708
692
            state._changes_aborted = True
709
693
            state.save()
710
694
        finally:
723
707
 
724
708
    def test_initialize(self):
725
709
        expected_result = ([], [
726
 
            ((b'', b'', b'TREE_ROOT'),  # common details
727
 
             [(b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
728
 
              ])
 
710
            (('', '', 'TREE_ROOT'), # common details
 
711
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
712
             ])
729
713
            ])
730
714
        state = dirstate.DirState.initialize('dirstate')
731
715
        try:
736
720
        # On win32 you can't read from a locked file, even within the same
737
721
        # process. So we have to unlock and release before we check the file
738
722
        # contents.
739
 
        self.assertFileEqual(b''.join(lines), 'dirstate')
740
 
        state.lock_read()  # check_state_with_reopen will unlock
 
723
        self.assertFileEqual(''.join(lines), 'dirstate')
 
724
        state.lock_read() # check_state_with_reopen will unlock
741
725
        self.check_state_with_reopen(expected_result, state)
742
726
 
743
727
 
755
739
        state = self.create_dirstate_with_root_and_subdir()
756
740
        self.addCleanup(state.unlock)
757
741
        id_index = state._get_id_index()
758
 
        self.assertEqual([b'a-root-value', b'subdir-id'], sorted(id_index))
759
 
        state.add('file-name', b'file-id', 'file', None, '')
760
 
        self.assertEqual([b'a-root-value', b'file-id', b'subdir-id'],
761
 
                         sorted(id_index))
762
 
        state.update_minimal((b'', b'new-name', b'file-id'), b'f',
763
 
                             path_utf8=b'new-name')
764
 
        self.assertEqual([b'a-root-value', b'file-id', b'subdir-id'],
765
 
                         sorted(id_index))
766
 
        self.assertEqual([(b'', b'new-name', b'file-id')],
767
 
                         sorted(id_index[b'file-id']))
 
742
        self.assertEqual(['a-root-value', 'subdir-id'], sorted(id_index))
 
743
        state.add('file-name', 'file-id', 'file', None, '')
 
744
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
 
745
                         sorted(id_index))
 
746
        state.update_minimal(('', 'new-name', 'file-id'), 'f',
 
747
                             path_utf8='new-name')
 
748
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
 
749
                         sorted(id_index))
 
750
        self.assertEqual([('', 'new-name', 'file-id')],
 
751
                         sorted(id_index['file-id']))
768
752
        state._validate()
769
753
 
770
754
    def test_set_state_from_inventory_no_content_no_parents(self):
773
757
        inv = tree1.root_inventory
774
758
        root_id = inv.path2id('')
775
759
        expected_result = [], [
776
 
            ((b'', b'', root_id), [
777
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT)])]
 
760
            (('', '', root_id), [
 
761
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
778
762
        state = dirstate.DirState.initialize('dirstate')
779
763
        try:
780
764
            state.set_state_from_inventory(inv)
794
778
        inv = tree1.root_inventory
795
779
        root_id = inv.path2id('')
796
780
        expected_result = [], [
797
 
            ((b'', b'', root_id), [
798
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT)])]
 
781
            (('', '', root_id), [
 
782
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
799
783
        state = dirstate.DirState.initialize('dirstate')
800
784
        try:
801
785
            state.set_state_from_scratch(inv, [], [])
815
799
        inv = tree1.root_inventory
816
800
        root_id = inv.path2id('')
817
801
        rev_tree1 = tree1.branch.repository.revision_tree(revid1)
818
 
        d_entry = (b'd', b'', 0, False, dirstate.DirState.NULLSTAT)
819
 
        parent_entry = (b'd', b'', 0, False, revid1)
 
802
        d_entry = ('d', '', 0, False, dirstate.DirState.NULLSTAT)
 
803
        parent_entry = ('d', '', 0, False, revid1)
820
804
        expected_result = [revid1], [
821
 
            ((b'', b'', root_id), [d_entry, parent_entry])]
 
805
            (('', '', root_id), [d_entry, parent_entry])]
822
806
        state = dirstate.DirState.initialize('dirstate')
823
807
        try:
824
808
            state.set_state_from_scratch(inv, [(revid1, rev_tree1)], [])
840
824
 
841
825
        tree = self.make_branch_and_tree('.')
842
826
        # depends on the default format using dirstate...
843
 
        with tree.lock_write():
 
827
        tree.lock_write()
 
828
        try:
844
829
            # make a dirstate with some valid hashcache data
845
830
            # file on disk, but that's not needed for this test
846
 
            foo_contents = b'contents of foo'
 
831
            foo_contents = 'contents of foo'
847
832
            self.build_tree_contents([('foo', foo_contents)])
848
 
            tree.add('foo', b'foo-id')
 
833
            tree.add('foo', 'foo-id')
849
834
 
850
835
            foo_stat = os.stat('foo')
851
836
            foo_packed = dirstate.pack_stat(foo_stat)
854
839
 
855
840
            # should not be cached yet, because the file's too fresh
856
841
            self.assertEqual(
857
 
                ((b'', b'foo', b'foo-id',),
858
 
                 [(b'f', b'', 0, False, dirstate.DirState.NULLSTAT)]),
859
 
                tree._dirstate._get_entry(0, b'foo-id'))
 
842
                (('', 'foo', 'foo-id',),
 
843
                 [('f', '', 0, False, dirstate.DirState.NULLSTAT)]),
 
844
                tree._dirstate._get_entry(0, 'foo-id'))
860
845
            # poke in some hashcache information - it wouldn't normally be
861
846
            # stored because it's too fresh
862
847
            tree._dirstate.update_minimal(
863
 
                (b'', b'foo', b'foo-id'),
864
 
                b'f', False, foo_sha, foo_packed, foo_size, b'foo')
 
848
                ('', 'foo', 'foo-id'),
 
849
                'f', False, foo_sha, foo_packed, foo_size, 'foo')
865
850
            # now should be cached
866
851
            self.assertEqual(
867
 
                ((b'', b'foo', b'foo-id',),
868
 
                 [(b'f', foo_sha, foo_size, False, foo_packed)]),
869
 
                tree._dirstate._get_entry(0, b'foo-id'))
 
852
                (('', 'foo', 'foo-id',),
 
853
                 [('f', foo_sha, foo_size, False, foo_packed)]),
 
854
                tree._dirstate._get_entry(0, 'foo-id'))
870
855
 
871
856
            # extract the inventory, and add something to it
872
857
            inv = tree._get_root_inventory()
873
858
            # should see the file we poked in...
874
 
            self.assertTrue(inv.has_id(b'foo-id'))
 
859
            self.assertTrue(inv.has_id('foo-id'))
875
860
            self.assertTrue(inv.has_filename('foo'))
876
 
            inv.add_path('bar', 'file', b'bar-id')
 
861
            inv.add_path('bar', 'file', 'bar-id')
877
862
            tree._dirstate._validate()
878
863
            # this used to cause it to lose its hashcache
879
864
            tree._dirstate.set_state_from_inventory(inv)
880
865
            tree._dirstate._validate()
 
866
        finally:
 
867
            tree.unlock()
881
868
 
882
 
        with tree.lock_read():
 
869
        tree.lock_read()
 
870
        try:
883
871
            # now check that the state still has the original hashcache value
884
872
            state = tree._dirstate
885
873
            state._validate()
886
 
            foo_tuple = state._get_entry(0, path_utf8=b'foo')
 
874
            foo_tuple = state._get_entry(0, path_utf8='foo')
887
875
            self.assertEqual(
888
 
                ((b'', b'foo', b'foo-id',),
889
 
                 [(b'f', foo_sha, len(foo_contents), False,
 
876
                (('', 'foo', 'foo-id',),
 
877
                 [('f', foo_sha, len(foo_contents), False,
890
878
                   dirstate.pack_stat(foo_stat))]),
891
879
                foo_tuple)
 
880
        finally:
 
881
            tree.unlock()
892
882
 
893
883
    def test_set_state_from_inventory_mixed_paths(self):
894
884
        tree1 = self.make_branch_and_tree('tree1')
897
887
        tree1.lock_write()
898
888
        try:
899
889
            tree1.add(['a', 'a/b', 'a-b', 'a/b/foo', 'a-b/bar'],
900
 
                      [b'a-id', b'b-id', b'a-b-id', b'foo-id', b'bar-id'])
901
 
            tree1.commit('rev1', rev_id=b'rev1')
902
 
            root_id = tree1.path2id('')
 
890
                      ['a-id', 'b-id', 'a-b-id', 'foo-id', 'bar-id'])
 
891
            tree1.commit('rev1', rev_id='rev1')
 
892
            root_id = tree1.get_root_id()
903
893
            inv = tree1.root_inventory
904
894
        finally:
905
895
            tree1.unlock()
906
 
        expected_result1 = [(b'', b'', root_id, b'd'),
907
 
                            (b'', b'a', b'a-id', b'd'),
908
 
                            (b'', b'a-b', b'a-b-id', b'd'),
909
 
                            (b'a', b'b', b'b-id', b'd'),
910
 
                            (b'a/b', b'foo', b'foo-id', b'f'),
911
 
                            (b'a-b', b'bar', b'bar-id', b'f'),
912
 
                            ]
913
 
        expected_result2 = [(b'', b'', root_id, b'd'),
914
 
                            (b'', b'a', b'a-id', b'd'),
915
 
                            (b'', b'a-b', b'a-b-id', b'd'),
916
 
                            (b'a-b', b'bar', b'bar-id', b'f'),
917
 
                            ]
 
896
        expected_result1 = [('', '', root_id, 'd'),
 
897
                            ('', 'a', 'a-id', 'd'),
 
898
                            ('', 'a-b', 'a-b-id', 'd'),
 
899
                            ('a', 'b', 'b-id', 'd'),
 
900
                            ('a/b', 'foo', 'foo-id', 'f'),
 
901
                            ('a-b', 'bar', 'bar-id', 'f'),
 
902
                           ]
 
903
        expected_result2 = [('', '', root_id, 'd'),
 
904
                            ('', 'a', 'a-id', 'd'),
 
905
                            ('', 'a-b', 'a-b-id', 'd'),
 
906
                            ('a-b', 'bar', 'bar-id', 'f'),
 
907
                           ]
918
908
        state = dirstate.DirState.initialize('dirstate')
919
909
        try:
920
910
            state.set_state_from_inventory(inv)
922
912
            for entry in state._iter_entries():
923
913
                values.append(entry[0] + entry[1][0][:1])
924
914
            self.assertEqual(expected_result1, values)
925
 
            inv.delete(b'b-id')
 
915
            del inv['b-id']
926
916
            state.set_state_from_inventory(inv)
927
917
            values = []
928
918
            for entry in state._iter_entries():
936
926
        state = dirstate.DirState.initialize('dirstate')
937
927
        try:
938
928
            # check precondition to be sure the state does change appropriately.
939
 
            root_entry = ((b'', b'', b'TREE_ROOT'), [
940
 
                          (b'd', b'', 0, False, b'x' * 32)])
 
929
            root_entry = (('', '', 'TREE_ROOT'), [('d', '', 0, False, 'x'*32)])
941
930
            self.assertEqual([root_entry], list(state._iter_entries()))
942
 
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=b''))
 
931
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
943
932
            self.assertEqual(root_entry,
944
 
                             state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
 
933
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
945
934
            self.assertEqual((None, None),
946
 
                             state._get_entry(0, fileid_utf8=b'second-root-id'))
947
 
            state.set_path_id(b'', b'second-root-id')
948
 
            new_root_entry = ((b'', b'', b'second-root-id'),
949
 
                              [(b'd', b'', 0, False, b'x' * 32)])
 
935
                             state._get_entry(0, fileid_utf8='second-root-id'))
 
936
            state.set_path_id('', 'second-root-id')
 
937
            new_root_entry = (('', '', 'second-root-id'),
 
938
                              [('d', '', 0, False, 'x'*32)])
950
939
            expected_rows = [new_root_entry]
951
940
            self.assertEqual(expected_rows, list(state._iter_entries()))
952
 
            self.assertEqual(
953
 
                new_root_entry, state._get_entry(0, path_utf8=b''))
954
 
            self.assertEqual(new_root_entry,
955
 
                             state._get_entry(0, fileid_utf8=b'second-root-id'))
 
941
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
 
942
            self.assertEqual(new_root_entry, 
 
943
                             state._get_entry(0, fileid_utf8='second-root-id'))
956
944
            self.assertEqual((None, None),
957
 
                             state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
 
945
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
958
946
            # should work across save too
959
947
            state.save()
960
948
        finally:
971
959
        """Set the root file id in a dirstate with parents"""
972
960
        mt = self.make_branch_and_tree('mt')
973
961
        # in case the default tree format uses a different root id
974
 
        mt.set_root_id(b'TREE_ROOT')
975
 
        mt.commit('foo', rev_id=b'parent-revid')
976
 
        rt = mt.branch.repository.revision_tree(b'parent-revid')
 
962
        mt.set_root_id('TREE_ROOT')
 
963
        mt.commit('foo', rev_id='parent-revid')
 
964
        rt = mt.branch.repository.revision_tree('parent-revid')
977
965
        state = dirstate.DirState.initialize('dirstate')
978
966
        state._validate()
979
967
        try:
980
 
            state.set_parent_trees([(b'parent-revid', rt)], ghosts=[])
981
 
            root_entry = ((b'', b'', b'TREE_ROOT'),
982
 
                          [(b'd', b'', 0, False, b'x' * 32),
983
 
                           (b'd', b'', 0, False, b'parent-revid')])
984
 
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=b''))
 
968
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
 
969
            root_entry = (('', '', 'TREE_ROOT'),
 
970
                          [('d', '', 0, False, 'x'*32),
 
971
                           ('d', '', 0, False, 'parent-revid')])
 
972
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
985
973
            self.assertEqual(root_entry,
986
 
                             state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
 
974
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
987
975
            self.assertEqual((None, None),
988
 
                             state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
989
 
            state.set_path_id(b'', b'Asecond-root-id')
 
976
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
 
977
            state.set_path_id('', 'Asecond-root-id')
990
978
            state._validate()
991
979
            # now see that it is what we expected
992
 
            old_root_entry = ((b'', b'', b'TREE_ROOT'),
993
 
                              [(b'a', b'', 0, False, b''),
994
 
                               (b'd', b'', 0, False, b'parent-revid')])
995
 
            new_root_entry = ((b'', b'', b'Asecond-root-id'),
996
 
                              [(b'd', b'', 0, False, b''),
997
 
                               (b'a', b'', 0, False, b'')])
 
980
            old_root_entry = (('', '', 'TREE_ROOT'),
 
981
                              [('a', '', 0, False, ''),
 
982
                               ('d', '', 0, False, 'parent-revid')])
 
983
            new_root_entry = (('', '', 'Asecond-root-id'),
 
984
                              [('d', '', 0, False, ''),
 
985
                               ('a', '', 0, False, '')])
998
986
            expected_rows = [new_root_entry, old_root_entry]
999
987
            state._validate()
1000
988
            self.assertEqual(expected_rows, list(state._iter_entries()))
1001
 
            self.assertEqual(
1002
 
                new_root_entry, state._get_entry(0, path_utf8=b''))
1003
 
            self.assertEqual(
1004
 
                old_root_entry, state._get_entry(1, path_utf8=b''))
 
989
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
 
990
            self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
1005
991
            self.assertEqual((None, None),
1006
 
                             state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
 
992
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
1007
993
            self.assertEqual(old_root_entry,
1008
 
                             state._get_entry(1, fileid_utf8=b'TREE_ROOT'))
 
994
                             state._get_entry(1, fileid_utf8='TREE_ROOT'))
1009
995
            self.assertEqual(new_root_entry,
1010
 
                             state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
 
996
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
1011
997
            self.assertEqual((None, None),
1012
 
                             state._get_entry(1, fileid_utf8=b'Asecond-root-id'))
 
998
                             state._get_entry(1, fileid_utf8='Asecond-root-id'))
1013
999
            # should work across save too
1014
1000
            state.save()
1015
1001
        finally:
1026
1012
        state.lock_write()
1027
1013
        try:
1028
1014
            state._validate()
1029
 
            state.set_path_id(b'', b'tree-root-2')
 
1015
            state.set_path_id('', 'tree-root-2')
1030
1016
            state._validate()
1031
1017
        finally:
1032
1018
            state.unlock()
1040
1026
            revid1 = tree1.commit('foo')
1041
1027
        finally:
1042
1028
            tree1.unlock()
1043
 
        branch2 = tree1.branch.controldir.clone('tree2').open_branch()
 
1029
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
1044
1030
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
1045
1031
        tree2.lock_write()
1046
1032
        try:
1047
1033
            revid2 = tree2.commit('foo')
1048
 
            root_id = tree2.path2id('')
 
1034
            root_id = tree2.get_root_id()
1049
1035
        finally:
1050
1036
            tree2.unlock()
1051
1037
        state = dirstate.DirState.initialize('dirstate')
1052
1038
        try:
1053
 
            state.set_path_id(b'', root_id)
 
1039
            state.set_path_id('', root_id)
1054
1040
            state.set_parent_trees(
1055
1041
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1056
1042
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
1057
 
                 (b'ghost-rev', None)),
1058
 
                [b'ghost-rev'])
 
1043
                 ('ghost-rev', None)),
 
1044
                ['ghost-rev'])
1059
1045
            # check we can reopen and use the dirstate after setting parent
1060
1046
            # trees.
1061
1047
            state._validate()
1066
1052
        state = dirstate.DirState.on_file('dirstate')
1067
1053
        state.lock_write()
1068
1054
        try:
1069
 
            self.assertEqual([revid1, revid2, b'ghost-rev'],
 
1055
            self.assertEqual([revid1, revid2, 'ghost-rev'],
1070
1056
                             state.get_parent_ids())
1071
1057
            # iterating the entire state ensures that the state is parsable.
1072
1058
            list(state._iter_entries())
1073
1059
            # be sure that it sets not appends - change it
1074
1060
            state.set_parent_trees(
1075
1061
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1076
 
                 (b'ghost-rev', None)),
1077
 
                [b'ghost-rev'])
 
1062
                 ('ghost-rev', None)),
 
1063
                ['ghost-rev'])
1078
1064
            # and now put it back.
1079
1065
            state.set_parent_trees(
1080
1066
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1081
1067
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
1082
 
                 (b'ghost-rev', tree2.branch.repository.revision_tree(
1083
 
                     _mod_revision.NULL_REVISION))),
1084
 
                [b'ghost-rev'])
1085
 
            self.assertEqual([revid1, revid2, b'ghost-rev'],
 
1068
                 ('ghost-rev', tree2.branch.repository.revision_tree(
 
1069
                                   _mod_revision.NULL_REVISION))),
 
1070
                ['ghost-rev'])
 
1071
            self.assertEqual([revid1, revid2, 'ghost-rev'],
1086
1072
                             state.get_parent_ids())
1087
1073
            # the ghost should be recorded as such by set_parent_trees.
1088
 
            self.assertEqual([b'ghost-rev'], state.get_ghosts())
 
1074
            self.assertEqual(['ghost-rev'], state.get_ghosts())
1089
1075
            self.assertEqual(
1090
 
                [((b'', b'', root_id), [
1091
 
                  (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),
1092
 
                  (b'd', b'', 0, False, revid1),
1093
 
                  (b'd', b'', 0, False, revid1)
 
1076
                [(('', '', root_id), [
 
1077
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
 
1078
                  ('d', '', 0, False, revid1),
 
1079
                  ('d', '', 0, False, revid1)
1094
1080
                  ])],
1095
1081
                list(state._iter_entries()))
1096
1082
        finally:
1105
1091
        tree1.lock_write()
1106
1092
        try:
1107
1093
            tree1.add('')
1108
 
            tree1.add(['a file'], [b'file-id'], ['file'])
1109
 
            tree1.put_file_bytes_non_atomic('a file', b'file-content')
 
1094
            tree1.add(['a file'], ['file-id'], ['file'])
 
1095
            tree1.put_file_bytes_non_atomic('file-id', 'file-content')
1110
1096
            revid1 = tree1.commit('foo')
1111
1097
        finally:
1112
1098
            tree1.unlock()
1113
 
        branch2 = tree1.branch.controldir.clone('tree2').open_branch()
 
1099
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
1114
1100
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
1115
1101
        tree2.lock_write()
1116
1102
        try:
1117
 
            tree2.put_file_bytes_non_atomic('a file', b'new file-content')
 
1103
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
1118
1104
            revid2 = tree2.commit('foo')
1119
 
            root_id = tree2.path2id('')
 
1105
            root_id = tree2.get_root_id()
1120
1106
        finally:
1121
1107
            tree2.unlock()
1122
1108
        # check the layout in memory
1123
 
        expected_result = [revid1, revid2], [
1124
 
            ((b'', b'', root_id), [
1125
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),
1126
 
             (b'd', b'', 0, False, revid1),
1127
 
             (b'd', b'', 0, False, revid1)
 
1109
        expected_result = [revid1.encode('utf8'), revid2.encode('utf8')], [
 
1110
            (('', '', root_id), [
 
1111
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
 
1112
             ('d', '', 0, False, revid1.encode('utf8')),
 
1113
             ('d', '', 0, False, revid1.encode('utf8'))
1128
1114
             ]),
1129
 
            ((b'', b'a file', b'file-id'), [
1130
 
             (b'a', b'', 0, False, b''),
1131
 
             (b'f', b'2439573625385400f2a669657a7db6ae7515d371', 12, False,
1132
 
              revid1),
1133
 
             (b'f', b'542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False,
1134
 
              revid2)
 
1115
            (('', 'a file', 'file-id'), [
 
1116
             ('a', '', 0, False, ''),
 
1117
             ('f', '2439573625385400f2a669657a7db6ae7515d371', 12, False,
 
1118
              revid1.encode('utf8')),
 
1119
             ('f', '542e57dc1cda4af37cb8e55ec07ce60364bb3c7d', 16, False,
 
1120
              revid2.encode('utf8'))
1135
1121
             ])
1136
1122
            ]
1137
1123
        state = dirstate.DirState.initialize('dirstate')
1138
1124
        try:
1139
 
            state.set_path_id(b'', root_id)
 
1125
            state.set_path_id('', root_id)
1140
1126
            state.set_parent_trees(
1141
1127
                ((revid1, tree1.branch.repository.revision_tree(revid1)),
1142
1128
                 (revid2, tree2.branch.repository.revision_tree(revid2)),
1148
1134
            # check_state_with_reopen will unlock
1149
1135
            self.check_state_with_reopen(expected_result, state)
1150
1136
 
1151
 
    # add a path via _set_data - so we dont need delta work, just
 
1137
    ### add a path via _set_data - so we dont need delta work, just
1152
1138
    # raw data in, and ensure that it comes out via get_lines happily.
1153
1139
 
1154
1140
    def test_add_path_to_root_no_parents_all_data(self):
1159
1145
        # the 1*20 is the sha1 pretend value.
1160
1146
        state = dirstate.DirState.initialize('dirstate')
1161
1147
        expected_entries = [
1162
 
            ((b'', b'', b'TREE_ROOT'), [
1163
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
 
1148
            (('', '', 'TREE_ROOT'), [
 
1149
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1164
1150
             ]),
1165
 
            ((b'', b'a file', b'a-file-id'), [
1166
 
             (b'f', b'1' * 20, 19, False, dirstate.pack_stat(stat)),  # current tree
 
1151
            (('', 'a file', 'a-file-id'), [
 
1152
             ('f', '1'*20, 19, False, dirstate.pack_stat(stat)), # current tree
1167
1153
             ]),
1168
1154
            ]
1169
1155
        try:
1170
 
            state.add('a file', b'a-file-id', 'file', stat, b'1' * 20)
 
1156
            state.add('a file', 'a-file-id', 'file', stat, '1'*20)
1171
1157
            # having added it, it should be in the output of iter_entries.
1172
1158
            self.assertEqual(expected_entries, list(state._iter_entries()))
1173
1159
            # saving and reloading should not affect this.
1190
1176
        state = dirstate.DirState.initialize('dirstate')
1191
1177
        self.addCleanup(state.unlock)
1192
1178
        self.assertRaises(errors.NotVersionedError, state.add,
1193
 
                          'unversioned/a file', b'a-file-id', 'file', None, None)
 
1179
                          'unversioned/a file', 'a-file-id', 'file', None, None)
1194
1180
 
1195
1181
    def test_add_directory_to_root_no_parents_all_data(self):
1196
1182
        # The most trivial addition of a dir is when there are no parents and
1198
1184
        self.build_tree(['a dir/'])
1199
1185
        stat = os.lstat('a dir')
1200
1186
        expected_entries = [
1201
 
            ((b'', b'', b'TREE_ROOT'), [
1202
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
 
1187
            (('', '', 'TREE_ROOT'), [
 
1188
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1203
1189
             ]),
1204
 
            ((b'', b'a dir', b'a dir id'), [
1205
 
             (b'd', b'', 0, False, dirstate.pack_stat(stat)),  # current tree
 
1190
            (('', 'a dir', 'a dir id'), [
 
1191
             ('d', '', 0, False, dirstate.pack_stat(stat)), # current tree
1206
1192
             ]),
1207
1193
            ]
1208
1194
        state = dirstate.DirState.initialize('dirstate')
1209
1195
        try:
1210
 
            state.add('a dir', b'a dir id', 'directory', stat, None)
 
1196
            state.add('a dir', 'a dir id', 'directory', stat, None)
1211
1197
            # having added it, it should be in the output of iter_entries.
1212
1198
            self.assertEqual(expected_entries, list(state._iter_entries()))
1213
1199
            # saving and reloading should not affect this.
1228
1214
        os.symlink(target, link_name)
1229
1215
        stat = os.lstat(link_name)
1230
1216
        expected_entries = [
1231
 
            ((b'', b'', b'TREE_ROOT'), [
1232
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
 
1217
            (('', '', 'TREE_ROOT'), [
 
1218
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1233
1219
             ]),
1234
 
            ((b'', link_name.encode('UTF-8'), b'a link id'), [
1235
 
             (b'l', target.encode('UTF-8'), stat[6],
1236
 
              False, dirstate.pack_stat(stat)),  # current tree
 
1220
            (('', link_name.encode('UTF-8'), 'a link id'), [
 
1221
             ('l', target.encode('UTF-8'), stat[6],
 
1222
              False, dirstate.pack_stat(stat)), # current tree
1237
1223
             ]),
1238
1224
            ]
1239
1225
        state = dirstate.DirState.initialize('dirstate')
1240
1226
        try:
1241
 
            state.add(link_name, b'a link id', 'symlink', stat,
 
1227
            state.add(link_name, 'a link id', 'symlink', stat,
1242
1228
                      target.encode('UTF-8'))
1243
1229
            # having added it, it should be in the output of iter_entries.
1244
1230
            self.assertEqual(expected_entries, list(state._iter_entries()))
1252
1238
        self.assertEqual(expected_entries, list(state._iter_entries()))
1253
1239
 
1254
1240
    def test_add_symlink_to_root_no_parents_all_data(self):
1255
 
        self._test_add_symlink_to_root_no_parents_all_data(
1256
 
            u'a link', u'target')
 
1241
        self._test_add_symlink_to_root_no_parents_all_data('a link', 'target')
1257
1242
 
1258
1243
    def test_add_symlink_unicode_to_root_no_parents_all_data(self):
1259
1244
        self.requireFeature(features.UnicodeFilenameFeature)
1266
1251
        dirstat = os.lstat('a dir')
1267
1252
        filestat = os.lstat('a dir/a file')
1268
1253
        expected_entries = [
1269
 
            ((b'', b'', b'TREE_ROOT'), [
1270
 
             (b'd', b'', 0, False, dirstate.DirState.NULLSTAT),  # current tree
1271
 
             ]),
1272
 
            ((b'', b'a dir', b'a dir id'), [
1273
 
             (b'd', b'', 0, False, dirstate.pack_stat(dirstat)),  # current tree
1274
 
             ]),
1275
 
            ((b'a dir', b'a file', b'a-file-id'), [
1276
 
             (b'f', b'1' * 20, 25, False,
1277
 
              dirstate.pack_stat(filestat)),  # current tree details
 
1254
            (('', '', 'TREE_ROOT'), [
 
1255
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
 
1256
             ]),
 
1257
            (('', 'a dir', 'a dir id'), [
 
1258
             ('d', '', 0, False, dirstate.pack_stat(dirstat)), # current tree
 
1259
             ]),
 
1260
            (('a dir', 'a file', 'a-file-id'), [
 
1261
             ('f', '1'*20, 25, False,
 
1262
              dirstate.pack_stat(filestat)), # current tree details
1278
1263
             ]),
1279
1264
            ]
1280
1265
        state = dirstate.DirState.initialize('dirstate')
1281
1266
        try:
1282
 
            state.add('a dir', b'a dir id', 'directory', dirstat, None)
1283
 
            state.add('a dir/a file', b'a-file-id',
1284
 
                      'file', filestat, b'1' * 20)
 
1267
            state.add('a dir', 'a dir id', 'directory', dirstat, None)
 
1268
            state.add('a dir/a file', 'a-file-id', 'file', filestat, '1'*20)
1285
1269
            # added it, it should be in the output of iter_entries.
1286
1270
            self.assertEqual(expected_entries, list(state._iter_entries()))
1287
1271
            # saving and reloading should not affect this.
1297
1281
        # make a dirstate and add a tree reference
1298
1282
        state = dirstate.DirState.initialize('dirstate')
1299
1283
        expected_entry = (
1300
 
            (b'', b'subdir', b'subdir-id'),
1301
 
            [(b't', b'subtree-123123', 0, False,
1302
 
              b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')],
 
1284
            ('', 'subdir', 'subdir-id'),
 
1285
            [('t', 'subtree-123123', 0, False,
 
1286
              'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')],
1303
1287
            )
1304
1288
        try:
1305
 
            state.add('subdir', b'subdir-id', 'tree-reference',
1306
 
                      None, b'subtree-123123')
1307
 
            entry = state._get_entry(0, b'subdir-id', b'subdir')
 
1289
            state.add('subdir', 'subdir-id', 'tree-reference', None, 'subtree-123123')
 
1290
            entry = state._get_entry(0, 'subdir-id', 'subdir')
1308
1291
            self.assertEqual(entry, expected_entry)
1309
1292
            state._validate()
1310
1293
            state.save()
1314
1297
        state.lock_read()
1315
1298
        self.addCleanup(state.unlock)
1316
1299
        state._validate()
1317
 
        entry2 = state._get_entry(0, b'subdir-id', b'subdir')
 
1300
        entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1318
1301
        self.assertEqual(entry, entry2)
1319
1302
        self.assertEqual(entry, expected_entry)
1320
1303
        # and lookup by id should work too
1321
 
        entry2 = state._get_entry(0, fileid_utf8=b'subdir-id')
 
1304
        entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1322
1305
        self.assertEqual(entry, expected_entry)
1323
1306
 
1324
1307
    def test_add_forbidden_names(self):
1325
1308
        state = dirstate.DirState.initialize('dirstate')
1326
1309
        self.addCleanup(state.unlock)
1327
1310
        self.assertRaises(errors.BzrError,
1328
 
                          state.add, '.', b'ass-id', 'directory', None, None)
 
1311
            state.add, '.', 'ass-id', 'directory', None, None)
1329
1312
        self.assertRaises(errors.BzrError,
1330
 
                          state.add, '..', b'ass-id', 'directory', None, None)
 
1313
            state.add, '..', 'ass-id', 'directory', None, None)
1331
1314
 
1332
1315
    def test_set_state_with_rename_b_a_bug_395556(self):
1333
1316
        # bug 395556 uncovered a bug where the dirstate ends up with a false
1337
1320
        # incorrect absent in tree 1, and future changes go to pot.
1338
1321
        tree1 = self.make_branch_and_tree('tree1')
1339
1322
        self.build_tree(['tree1/b'])
1340
 
        with tree1.lock_write():
1341
 
            tree1.add(['b'], [b'b-id'])
1342
 
            root_id = tree1.path2id('')
 
1323
        tree1.lock_write()
 
1324
        try:
 
1325
            tree1.add(['b'], ['b-id'])
 
1326
            root_id = tree1.get_root_id()
1343
1327
            inv = tree1.root_inventory
1344
1328
            state = dirstate.DirState.initialize('dirstate')
1345
1329
            try:
1346
1330
                # Set the initial state with 'b'
1347
1331
                state.set_state_from_inventory(inv)
1348
 
                inv.rename(b'b-id', root_id, 'a')
 
1332
                inv.rename('b-id', root_id, 'a')
1349
1333
                # Set the new state with 'a', which currently corrupts.
1350
1334
                state.set_state_from_inventory(inv)
1351
 
                expected_result1 = [(b'', b'', root_id, b'd'),
1352
 
                                    (b'', b'a', b'b-id', b'f'),
1353
 
                                    ]
 
1335
                expected_result1 = [('', '', root_id, 'd'),
 
1336
                                    ('', 'a', 'b-id', 'f'),
 
1337
                                   ]
1354
1338
                values = []
1355
1339
                for entry in state._iter_entries():
1356
1340
                    values.append(entry[0] + entry[1][0][:1])
1357
1341
                self.assertEqual(expected_result1, values)
1358
1342
            finally:
1359
1343
                state.unlock()
 
1344
        finally:
 
1345
            tree1.unlock()
1360
1346
 
1361
1347
 
1362
1348
class TestDirStateHashUpdates(TestCaseWithDirState):
1383
1369
        tree = self.make_branch_and_tree('.')
1384
1370
        self.build_tree(['c', 'd'])
1385
1371
        tree.lock_write()
1386
 
        tree.add(['c', 'd'], [b'c-id', b'd-id'])
 
1372
        tree.add(['c', 'd'], ['c-id', 'd-id'])
1387
1373
        tree.commit('add c and d')
1388
1374
        state = InstrumentedDirState.on_file(tree.current_dirstate()._filename,
1389
1375
                                             worth_saving_limit=2)
1391
1377
        state.lock_write()
1392
1378
        self.addCleanup(state.unlock)
1393
1379
        state._read_dirblocks_if_needed()
1394
 
        state.adjust_time(+20)  # Allow things to be cached
 
1380
        state.adjust_time(+20) # Allow things to be cached
1395
1381
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1396
1382
                         state._dirblock_state)
1397
1383
        content = self._read_state_content(state)
1398
 
        self.do_update_entry(state, b'c')
 
1384
        self.do_update_entry(state, 'c')
1399
1385
        self.assertEqual(1, len(state._known_hash_changes))
1400
1386
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
1401
1387
                         state._dirblock_state)
1407
1393
        self.assertEqual(content, self._read_state_content(state))
1408
1394
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
1409
1395
                         state._dirblock_state)
1410
 
        self.do_update_entry(state, b'd')
 
1396
        self.do_update_entry(state, 'd')
1411
1397
        self.assertEqual(2, len(state._known_hash_changes))
1412
1398
        state.save()
1413
1399
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1420
1406
    def test_get_line_with_2_rows(self):
1421
1407
        state = self.create_dirstate_with_root_and_subdir()
1422
1408
        try:
1423
 
            self.assertEqual([b'#bazaar dirstate flat format 3\n',
1424
 
                              b'crc32: 41262208\n',
1425
 
                              b'num_entries: 2\n',
1426
 
                              b'0\x00\n\x00'
1427
 
                              b'0\x00\n\x00'
1428
 
                              b'\x00\x00a-root-value\x00'
1429
 
                              b'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1430
 
                              b'\x00subdir\x00subdir-id\x00'
1431
 
                              b'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
1432
 
                              ], state.get_lines())
 
1409
            self.assertEqual(['#bazaar dirstate flat format 3\n',
 
1410
                'crc32: 41262208\n',
 
1411
                'num_entries: 2\n',
 
1412
                '0\x00\n\x00'
 
1413
                '0\x00\n\x00'
 
1414
                '\x00\x00a-root-value\x00'
 
1415
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
 
1416
                '\x00subdir\x00subdir-id\x00'
 
1417
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00\n\x00'
 
1418
                ], state.get_lines())
1433
1419
        finally:
1434
1420
            state.unlock()
1435
1421
 
1437
1423
        state = self.create_dirstate_with_root()
1438
1424
        try:
1439
1425
            self.assertEqual(
1440
 
                b'\x00\x00a-root-value\x00d\x00\x000\x00n'
1441
 
                b'\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
 
1426
                '\x00\x00a-root-value\x00d\x00\x000\x00n'
 
1427
                '\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk',
1442
1428
                state._entry_to_line(state._dirblocks[0][1][0]))
1443
1429
        finally:
1444
1430
            state.unlock()
1445
1431
 
1446
1432
    def test_entry_to_line_with_parent(self):
1447
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1448
 
        root_entry = (b'', b'', b'a-root-value'), [
1449
 
            (b'd', b'', 0, False, packed_stat),  # current tree details
1450
 
            # first: a pointer to the current location
1451
 
            (b'a', b'dirname/basename', 0, False, b''),
 
1433
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
1434
        root_entry = ('', '', 'a-root-value'), [
 
1435
            ('d', '', 0, False, packed_stat), # current tree details
 
1436
             # first: a pointer to the current location
 
1437
            ('a', 'dirname/basename', 0, False, ''),
1452
1438
            ]
1453
1439
        state = dirstate.DirState.initialize('dirstate')
1454
1440
        try:
1455
1441
            self.assertEqual(
1456
 
                b'\x00\x00a-root-value\x00'
1457
 
                b'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1458
 
                b'a\x00dirname/basename\x000\x00n\x00',
 
1442
                '\x00\x00a-root-value\x00'
 
1443
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
 
1444
                'a\x00dirname/basename\x000\x00n\x00',
1459
1445
                state._entry_to_line(root_entry))
1460
1446
        finally:
1461
1447
            state.unlock()
1462
1448
 
1463
1449
    def test_entry_to_line_with_two_parents_at_different_paths(self):
1464
1450
        # / in the tree, at / in one parent and /dirname/basename in the other.
1465
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1466
 
        root_entry = (b'', b'', b'a-root-value'), [
1467
 
            (b'd', b'', 0, False, packed_stat),  # current tree details
1468
 
            (b'd', b'', 0, False, b'rev_id'),  # first parent details
1469
 
            # second: a pointer to the current location
1470
 
            (b'a', b'dirname/basename', 0, False, b''),
 
1451
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
1452
        root_entry = ('', '', 'a-root-value'), [
 
1453
            ('d', '', 0, False, packed_stat), # current tree details
 
1454
            ('d', '', 0, False, 'rev_id'), # first parent details
 
1455
             # second: a pointer to the current location
 
1456
            ('a', 'dirname/basename', 0, False, ''),
1471
1457
            ]
1472
1458
        state = dirstate.DirState.initialize('dirstate')
1473
1459
        try:
1474
1460
            self.assertEqual(
1475
 
                b'\x00\x00a-root-value\x00'
1476
 
                b'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
1477
 
                b'd\x00\x000\x00n\x00rev_id\x00'
1478
 
                b'a\x00dirname/basename\x000\x00n\x00',
 
1461
                '\x00\x00a-root-value\x00'
 
1462
                'd\x00\x000\x00n\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00'
 
1463
                'd\x00\x000\x00n\x00rev_id\x00'
 
1464
                'a\x00dirname/basename\x000\x00n\x00',
1479
1465
                state._entry_to_line(root_entry))
1480
1466
        finally:
1481
1467
            state.unlock()
1483
1469
    def test_iter_entries(self):
1484
1470
        # we should be able to iterate the dirstate entries from end to end
1485
1471
        # this is for get_lines to be easy to read.
1486
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
1472
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1487
1473
        dirblocks = []
1488
 
        root_entries = [((b'', b'', b'a-root-value'), [
1489
 
            (b'd', b'', 0, False, packed_stat),  # current tree details
 
1474
        root_entries = [(('', '', 'a-root-value'), [
 
1475
            ('d', '', 0, False, packed_stat), # current tree details
1490
1476
            ])]
1491
1477
        dirblocks.append(('', root_entries))
1492
1478
        # add two files in the root
1493
 
        subdir_entry = (b'', b'subdir', b'subdir-id'), [
1494
 
            (b'd', b'', 0, False, packed_stat),  # current tree details
 
1479
        subdir_entry = ('', 'subdir', 'subdir-id'), [
 
1480
            ('d', '', 0, False, packed_stat), # current tree details
1495
1481
            ]
1496
 
        afile_entry = (b'', b'afile', b'afile-id'), [
1497
 
            (b'f', b'sha1value', 34, False, packed_stat),  # current tree details
 
1482
        afile_entry = ('', 'afile', 'afile-id'), [
 
1483
            ('f', 'sha1value', 34, False, packed_stat), # current tree details
1498
1484
            ]
1499
1485
        dirblocks.append(('', [subdir_entry, afile_entry]))
1500
1486
        # and one in subdir
1501
 
        file_entry2 = (b'subdir', b'2file', b'2file-id'), [
1502
 
            (b'f', b'sha1value', 23, False, packed_stat),  # current tree details
 
1487
        file_entry2 = ('subdir', '2file', '2file-id'), [
 
1488
            ('f', 'sha1value', 23, False, packed_stat), # current tree details
1503
1489
            ]
1504
1490
        dirblocks.append(('subdir', [file_entry2]))
1505
1491
        state = dirstate.DirState.initialize('dirstate')
1515
1501
class TestGetBlockRowIndex(TestCaseWithDirState):
1516
1502
 
1517
1503
    def assertBlockRowIndexEqual(self, block_index, row_index, dir_present,
1518
 
                                 file_present, state, dirname, basename, tree_index):
 
1504
        file_present, state, dirname, basename, tree_index):
1519
1505
        self.assertEqual((block_index, row_index, dir_present, file_present),
1520
 
                         state._get_block_entry_index(dirname, basename, tree_index))
 
1506
            state._get_block_entry_index(dirname, basename, tree_index))
1521
1507
        if dir_present:
1522
1508
            block = state._dirblocks[block_index]
1523
1509
            self.assertEqual(dirname, block[0])
1529
1515
    def test_simple_structure(self):
1530
1516
        state = self.create_dirstate_with_root_and_subdir()
1531
1517
        self.addCleanup(state.unlock)
1532
 
        self.assertBlockRowIndexEqual(
1533
 
            1, 0, True, True, state, b'', b'subdir', 0)
1534
 
        self.assertBlockRowIndexEqual(
1535
 
            1, 0, True, False, state, b'', b'bdir', 0)
1536
 
        self.assertBlockRowIndexEqual(
1537
 
            1, 1, True, False, state, b'', b'zdir', 0)
1538
 
        self.assertBlockRowIndexEqual(
1539
 
            2, 0, False, False, state, b'a', b'foo', 0)
 
1518
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
 
1519
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
 
1520
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
 
1521
        self.assertBlockRowIndexEqual(2, 0, False, False, state, 'a', 'foo', 0)
1540
1522
        self.assertBlockRowIndexEqual(2, 0, False, False, state,
1541
 
                                      b'subdir', b'foo', 0)
 
1523
                                      'subdir', 'foo', 0)
1542
1524
 
1543
1525
    def test_complex_structure_exists(self):
1544
1526
        state = self.create_complex_dirstate()
1545
1527
        self.addCleanup(state.unlock)
1546
1528
        # Make sure we can find everything that exists
1547
 
        self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1548
 
        self.assertBlockRowIndexEqual(1, 0, True, True, state, b'', b'a', 0)
1549
 
        self.assertBlockRowIndexEqual(1, 1, True, True, state, b'', b'b', 0)
1550
 
        self.assertBlockRowIndexEqual(1, 2, True, True, state, b'', b'c', 0)
1551
 
        self.assertBlockRowIndexEqual(1, 3, True, True, state, b'', b'd', 0)
1552
 
        self.assertBlockRowIndexEqual(2, 0, True, True, state, b'a', b'e', 0)
1553
 
        self.assertBlockRowIndexEqual(2, 1, True, True, state, b'a', b'f', 0)
1554
 
        self.assertBlockRowIndexEqual(3, 0, True, True, state, b'b', b'g', 0)
 
1529
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
 
1530
        self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
 
1531
        self.assertBlockRowIndexEqual(1, 1, True, True, state, '', 'b', 0)
 
1532
        self.assertBlockRowIndexEqual(1, 2, True, True, state, '', 'c', 0)
 
1533
        self.assertBlockRowIndexEqual(1, 3, True, True, state, '', 'd', 0)
 
1534
        self.assertBlockRowIndexEqual(2, 0, True, True, state, 'a', 'e', 0)
 
1535
        self.assertBlockRowIndexEqual(2, 1, True, True, state, 'a', 'f', 0)
 
1536
        self.assertBlockRowIndexEqual(3, 0, True, True, state, 'b', 'g', 0)
1555
1537
        self.assertBlockRowIndexEqual(3, 1, True, True, state,
1556
 
                                      b'b', b'h\xc3\xa5', 0)
 
1538
                                      'b', 'h\xc3\xa5', 0)
1557
1539
 
1558
1540
    def test_complex_structure_missing(self):
1559
1541
        state = self.create_complex_dirstate()
1560
1542
        self.addCleanup(state.unlock)
1561
1543
        # Make sure things would be inserted in the right locations
1562
1544
        # '_' comes before 'a'
1563
 
        self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1564
 
        self.assertBlockRowIndexEqual(1, 0, True, False, state, b'', b'_', 0)
1565
 
        self.assertBlockRowIndexEqual(1, 1, True, False, state, b'', b'aa', 0)
 
1545
        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
 
1546
        self.assertBlockRowIndexEqual(1, 0, True, False, state, '', '_', 0)
 
1547
        self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'aa', 0)
1566
1548
        self.assertBlockRowIndexEqual(1, 4, True, False, state,
1567
 
                                      b'', b'h\xc3\xa5', 0)
1568
 
        self.assertBlockRowIndexEqual(2, 0, False, False, state, b'_', b'a', 0)
1569
 
        self.assertBlockRowIndexEqual(
1570
 
            3, 0, False, False, state, b'aa', b'a', 0)
1571
 
        self.assertBlockRowIndexEqual(
1572
 
            4, 0, False, False, state, b'bb', b'a', 0)
 
1549
                                      '', 'h\xc3\xa5', 0)
 
1550
        self.assertBlockRowIndexEqual(2, 0, False, False, state, '_', 'a', 0)
 
1551
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'aa', 'a', 0)
 
1552
        self.assertBlockRowIndexEqual(4, 0, False, False, state, 'bb', 'a', 0)
1573
1553
        # This would be inserted between a/ and b/
1574
 
        self.assertBlockRowIndexEqual(
1575
 
            3, 0, False, False, state, b'a/e', b'a', 0)
 
1554
        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'a/e', 'a', 0)
1576
1555
        # Put at the end
1577
 
        self.assertBlockRowIndexEqual(4, 0, False, False, state, b'e', b'a', 0)
 
1556
        self.assertBlockRowIndexEqual(4, 0, False, False, state, 'e', 'a', 0)
1578
1557
 
1579
1558
 
1580
1559
class TestGetEntry(TestCaseWithDirState):
1591
1570
    def test_simple_structure(self):
1592
1571
        state = self.create_dirstate_with_root_and_subdir()
1593
1572
        self.addCleanup(state.unlock)
1594
 
        self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1595
 
        self.assertEntryEqual(
1596
 
            b'', b'subdir', b'subdir-id', state, b'subdir', 0)
1597
 
        self.assertEntryEqual(None, None, None, state, b'missing', 0)
1598
 
        self.assertEntryEqual(None, None, None, state, b'missing/foo', 0)
1599
 
        self.assertEntryEqual(None, None, None, state, b'subdir/foo', 0)
 
1573
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
 
1574
        self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
 
1575
        self.assertEntryEqual(None, None, None, state, 'missing', 0)
 
1576
        self.assertEntryEqual(None, None, None, state, 'missing/foo', 0)
 
1577
        self.assertEntryEqual(None, None, None, state, 'subdir/foo', 0)
1600
1578
 
1601
1579
    def test_complex_structure_exists(self):
1602
1580
        state = self.create_complex_dirstate()
1603
1581
        self.addCleanup(state.unlock)
1604
 
        self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1605
 
        self.assertEntryEqual(b'', b'a', b'a-dir', state, b'a', 0)
1606
 
        self.assertEntryEqual(b'', b'b', b'b-dir', state, b'b', 0)
1607
 
        self.assertEntryEqual(b'', b'c', b'c-file', state, b'c', 0)
1608
 
        self.assertEntryEqual(b'', b'd', b'd-file', state, b'd', 0)
1609
 
        self.assertEntryEqual(b'a', b'e', b'e-dir', state, b'a/e', 0)
1610
 
        self.assertEntryEqual(b'a', b'f', b'f-file', state, b'a/f', 0)
1611
 
        self.assertEntryEqual(b'b', b'g', b'g-file', state, b'b/g', 0)
1612
 
        self.assertEntryEqual(b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file', state,
1613
 
                              b'b/h\xc3\xa5', 0)
 
1582
        self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
 
1583
        self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
 
1584
        self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
 
1585
        self.assertEntryEqual('', 'c', 'c-file', state, 'c', 0)
 
1586
        self.assertEntryEqual('', 'd', 'd-file', state, 'd', 0)
 
1587
        self.assertEntryEqual('a', 'e', 'e-dir', state, 'a/e', 0)
 
1588
        self.assertEntryEqual('a', 'f', 'f-file', state, 'a/f', 0)
 
1589
        self.assertEntryEqual('b', 'g', 'g-file', state, 'b/g', 0)
 
1590
        self.assertEntryEqual('b', 'h\xc3\xa5', 'h-\xc3\xa5-file', state,
 
1591
                              'b/h\xc3\xa5', 0)
1614
1592
 
1615
1593
    def test_complex_structure_missing(self):
1616
1594
        state = self.create_complex_dirstate()
1617
1595
        self.addCleanup(state.unlock)
1618
 
        self.assertEntryEqual(None, None, None, state, b'_', 0)
1619
 
        self.assertEntryEqual(None, None, None, state, b'_\xc3\xa5', 0)
1620
 
        self.assertEntryEqual(None, None, None, state, b'a/b', 0)
1621
 
        self.assertEntryEqual(None, None, None, state, b'c/d', 0)
 
1596
        self.assertEntryEqual(None, None, None, state, '_', 0)
 
1597
        self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
 
1598
        self.assertEntryEqual(None, None, None, state, 'a/b', 0)
 
1599
        self.assertEntryEqual(None, None, None, state, 'c/d', 0)
1622
1600
 
1623
1601
    def test_get_entry_uninitialized(self):
1624
1602
        """Calling get_entry will load data if it needs to"""
1635
1613
                             state._header_state)
1636
1614
            self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1637
1615
                             state._dirblock_state)
1638
 
            self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
 
1616
            self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1639
1617
        finally:
1640
1618
            state.unlock()
1641
1619
 
1665
1643
 
1666
1644
        :return: The dirstate, still write-locked.
1667
1645
        """
1668
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1669
 
        null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 
1646
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
1647
        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1670
1648
        NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1671
 
        root_entry = (b'', b'', b'a-root-value'), [
1672
 
            (b'd', b'', 0, False, packed_stat),
1673
 
            (b'd', b'', 0, False, b'parent-revid'),
1674
 
            ]
1675
 
        a_entry = (b'', b'a', b'a-dir'), [
1676
 
            (b'd', b'', 0, False, packed_stat),
1677
 
            (b'd', b'', 0, False, b'parent-revid'),
1678
 
            ]
1679
 
        b_entry = (b'', b'b', b'b-dir'), [
1680
 
            (b'd', b'', 0, False, packed_stat),
1681
 
            (b'd', b'', 0, False, b'parent-revid'),
1682
 
            ]
1683
 
        c_entry = (b'', b'c', b'c-file'), [
1684
 
            (b'f', null_sha, 10, False, packed_stat),
1685
 
            (b'r', b'b/j', 0, False, b''),
1686
 
            ]
1687
 
        d_entry = (b'', b'd', b'd-file'), [
1688
 
            (b'f', null_sha, 20, False, packed_stat),
1689
 
            (b'f', b'd', 20, False, b'parent-revid'),
1690
 
            ]
1691
 
        e_entry = (b'a', b'e', b'e-dir'), [
1692
 
            (b'd', b'', 0, False, packed_stat),
1693
 
            (b'd', b'', 0, False, b'parent-revid'),
1694
 
            ]
1695
 
        f_entry = (b'a', b'f', b'f-file'), [
1696
 
            (b'f', null_sha, 30, False, packed_stat),
1697
 
            (b'f', b'f', 20, False, b'parent-revid'),
1698
 
            ]
1699
 
        g_entry = (b'b', b'g', b'g-file'), [
1700
 
            (b'f', null_sha, 30, False, packed_stat),
1701
 
            NULL_PARENT_DETAILS,
1702
 
            ]
1703
 
        h_entry1 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file1'), [
1704
 
            (b'f', null_sha, 40, False, packed_stat),
1705
 
            NULL_PARENT_DETAILS,
1706
 
            ]
1707
 
        h_entry2 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file2'), [
1708
 
            NULL_PARENT_DETAILS,
1709
 
            (b'f', b'h', 20, False, b'parent-revid'),
1710
 
            ]
1711
 
        i_entry = (b'b', b'i', b'i-file'), [
1712
 
            NULL_PARENT_DETAILS,
1713
 
            (b'f', b'h', 20, False, b'parent-revid'),
1714
 
            ]
1715
 
        j_entry = (b'b', b'j', b'c-file'), [
1716
 
            (b'r', b'c', 0, False, b''),
1717
 
            (b'f', b'j', 20, False, b'parent-revid'),
 
1649
        root_entry = ('', '', 'a-root-value'), [
 
1650
            ('d', '', 0, False, packed_stat),
 
1651
            ('d', '', 0, False, 'parent-revid'),
 
1652
            ]
 
1653
        a_entry = ('', 'a', 'a-dir'), [
 
1654
            ('d', '', 0, False, packed_stat),
 
1655
            ('d', '', 0, False, 'parent-revid'),
 
1656
            ]
 
1657
        b_entry = ('', 'b', 'b-dir'), [
 
1658
            ('d', '', 0, False, packed_stat),
 
1659
            ('d', '', 0, False, 'parent-revid'),
 
1660
            ]
 
1661
        c_entry = ('', 'c', 'c-file'), [
 
1662
            ('f', null_sha, 10, False, packed_stat),
 
1663
            ('r', 'b/j', 0, False, ''),
 
1664
            ]
 
1665
        d_entry = ('', 'd', 'd-file'), [
 
1666
            ('f', null_sha, 20, False, packed_stat),
 
1667
            ('f', 'd', 20, False, 'parent-revid'),
 
1668
            ]
 
1669
        e_entry = ('a', 'e', 'e-dir'), [
 
1670
            ('d', '', 0, False, packed_stat),
 
1671
            ('d', '', 0, False, 'parent-revid'),
 
1672
            ]
 
1673
        f_entry = ('a', 'f', 'f-file'), [
 
1674
            ('f', null_sha, 30, False, packed_stat),
 
1675
            ('f', 'f', 20, False, 'parent-revid'),
 
1676
            ]
 
1677
        g_entry = ('b', 'g', 'g-file'), [
 
1678
            ('f', null_sha, 30, False, packed_stat),
 
1679
            NULL_PARENT_DETAILS,
 
1680
            ]
 
1681
        h_entry1 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file1'), [
 
1682
            ('f', null_sha, 40, False, packed_stat),
 
1683
            NULL_PARENT_DETAILS,
 
1684
            ]
 
1685
        h_entry2 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file2'), [
 
1686
            NULL_PARENT_DETAILS,
 
1687
            ('f', 'h', 20, False, 'parent-revid'),
 
1688
            ]
 
1689
        i_entry = ('b', 'i', 'i-file'), [
 
1690
            NULL_PARENT_DETAILS,
 
1691
            ('f', 'h', 20, False, 'parent-revid'),
 
1692
            ]
 
1693
        j_entry = ('b', 'j', 'c-file'), [
 
1694
            ('r', 'c', 0, False, ''),
 
1695
            ('f', 'j', 20, False, 'parent-revid'),
1718
1696
            ]
1719
1697
        dirblocks = []
1720
 
        dirblocks.append((b'', [root_entry]))
1721
 
        dirblocks.append((b'', [a_entry, b_entry, c_entry, d_entry]))
1722
 
        dirblocks.append((b'a', [e_entry, f_entry]))
1723
 
        dirblocks.append(
1724
 
            (b'b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
 
1698
        dirblocks.append(('', [root_entry]))
 
1699
        dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
 
1700
        dirblocks.append(('a', [e_entry, f_entry]))
 
1701
        dirblocks.append(('b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1725
1702
        state = dirstate.DirState.initialize('dirstate')
1726
1703
        state._validate()
1727
1704
        try:
1728
 
            state._set_data([b'parent'], dirblocks)
 
1705
            state._set_data(['parent'], dirblocks)
1729
1706
        except:
1730
1707
            state.unlock()
1731
1708
            raise
1735
1712
        state, dirblocks = self.create_dirstate_with_two_trees()
1736
1713
        self.addCleanup(state.unlock)
1737
1714
        expected_result = []
1738
 
        expected_result.append(dirblocks[3][1][2])  # h2
1739
 
        expected_result.append(dirblocks[3][1][3])  # i
1740
 
        expected_result.append(dirblocks[3][1][4])  # j
 
1715
        expected_result.append(dirblocks[3][1][2]) # h2
 
1716
        expected_result.append(dirblocks[3][1][3]) # i
 
1717
        expected_result.append(dirblocks[3][1][4]) # j
1741
1718
        self.assertEqual(expected_result,
1742
 
                         list(state._iter_child_entries(1, b'b')))
 
1719
            list(state._iter_child_entries(1, 'b')))
1743
1720
 
1744
1721
    def test_iter_child_root(self):
1745
1722
        state, dirblocks = self.create_dirstate_with_two_trees()
1746
1723
        self.addCleanup(state.unlock)
1747
1724
        expected_result = []
1748
 
        expected_result.append(dirblocks[1][1][0])  # a
1749
 
        expected_result.append(dirblocks[1][1][1])  # b
1750
 
        expected_result.append(dirblocks[1][1][3])  # d
1751
 
        expected_result.append(dirblocks[2][1][0])  # e
1752
 
        expected_result.append(dirblocks[2][1][1])  # f
1753
 
        expected_result.append(dirblocks[3][1][2])  # h2
1754
 
        expected_result.append(dirblocks[3][1][3])  # i
1755
 
        expected_result.append(dirblocks[3][1][4])  # j
 
1725
        expected_result.append(dirblocks[1][1][0]) # a
 
1726
        expected_result.append(dirblocks[1][1][1]) # b
 
1727
        expected_result.append(dirblocks[1][1][3]) # d
 
1728
        expected_result.append(dirblocks[2][1][0]) # e
 
1729
        expected_result.append(dirblocks[2][1][1]) # f
 
1730
        expected_result.append(dirblocks[3][1][2]) # h2
 
1731
        expected_result.append(dirblocks[3][1][3]) # i
 
1732
        expected_result.append(dirblocks[3][1][4]) # j
1756
1733
        self.assertEqual(expected_result,
1757
 
                         list(state._iter_child_entries(1, b'')))
 
1734
            list(state._iter_child_entries(1, '')))
1758
1735
 
1759
1736
 
1760
1737
class TestDirstateSortOrder(tests.TestCaseWithTransport):
1769
1746
        """
1770
1747
        dirs = ['a', 'a/a', 'a/a/a', 'a/a/a/a',
1771
1748
                'a-a', 'a/a-a', 'a/a/a-a', 'a/a/a/a-a',
1772
 
                ]
1773
 
        null_sha = b''
 
1749
               ]
 
1750
        null_sha = ''
1774
1751
        state = dirstate.DirState.initialize('dirstate')
1775
1752
        self.addCleanup(state.unlock)
1776
1753
 
1777
1754
        fake_stat = os.stat('dirstate')
1778
1755
        for d in dirs:
1779
 
            d_id = d.encode('utf-8').replace(b'/', b'_') + b'-id'
 
1756
            d_id = d.replace('/', '_')+'-id'
1780
1757
            file_path = d + '/f'
1781
 
            file_id = file_path.encode('utf-8').replace(b'/', b'_') + b'-id'
 
1758
            file_id = file_path.replace('/', '_')+'-id'
1782
1759
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1783
1760
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1784
1761
 
1785
 
        expected = [b'', b'', b'a',
1786
 
                    b'a/a', b'a/a/a', b'a/a/a/a',
1787
 
                    b'a/a/a/a-a', b'a/a/a-a', b'a/a-a', b'a-a',
1788
 
                    ]
1789
 
 
1790
 
        def split(p): return p.split(b'/')
 
1762
        expected = ['', '', 'a',
 
1763
                'a/a', 'a/a/a', 'a/a/a/a',
 
1764
                'a/a/a/a-a', 'a/a/a-a', 'a/a-a', 'a-a',
 
1765
               ]
 
1766
        split = lambda p:p.split('/')
1791
1767
        self.assertEqual(sorted(expected, key=split), expected)
1792
1768
        dirblock_names = [d[0] for d in state._dirblocks]
1793
1769
        self.assertEqual(expected, dirblock_names)
1795
1771
    def test_set_parent_trees_correct_order(self):
1796
1772
        """After calling set_parent_trees() we should maintain the order."""
1797
1773
        dirs = ['a', 'a-a', 'a/a']
1798
 
        null_sha = b''
 
1774
        null_sha = ''
1799
1775
        state = dirstate.DirState.initialize('dirstate')
1800
1776
        self.addCleanup(state.unlock)
1801
1777
 
1802
1778
        fake_stat = os.stat('dirstate')
1803
1779
        for d in dirs:
1804
 
            d_id = d.encode('utf-8').replace(b'/', b'_') + b'-id'
 
1780
            d_id = d.replace('/', '_')+'-id'
1805
1781
            file_path = d + '/f'
1806
 
            file_id = file_path.encode('utf-8').replace(b'/', b'_') + b'-id'
 
1782
            file_id = file_path.replace('/', '_')+'-id'
1807
1783
            state.add(d, d_id, 'directory', fake_stat, null_sha)
1808
1784
            state.add(file_path, file_id, 'file', fake_stat, null_sha)
1809
1785
 
1810
 
        expected = [b'', b'', b'a', b'a/a', b'a-a']
 
1786
        expected = ['', '', 'a', 'a/a', 'a-a']
1811
1787
        dirblock_names = [d[0] for d in state._dirblocks]
1812
1788
        self.assertEqual(expected, dirblock_names)
1813
1789
 
1823
1799
class InstrumentedDirState(dirstate.DirState):
1824
1800
    """An DirState with instrumented sha1 functionality."""
1825
1801
 
1826
 
    def __init__(self, path, sha1_provider, worth_saving_limit=0,
1827
 
                 use_filesystem_for_exec=True):
1828
 
        super(InstrumentedDirState, self).__init__(
1829
 
            path, sha1_provider, worth_saving_limit=worth_saving_limit,
1830
 
            use_filesystem_for_exec=use_filesystem_for_exec)
 
1802
    def __init__(self, path, sha1_provider, worth_saving_limit=0):
 
1803
        super(InstrumentedDirState, self).__init__(path, sha1_provider,
 
1804
            worth_saving_limit=worth_saving_limit)
1831
1805
        self._time_offset = 0
1832
1806
        self._log = []
1833
1807
        # member is dynamically set in DirState.__init__ to turn on trace
1880
1854
    @staticmethod
1881
1855
    def from_stat(st):
1882
1856
        return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
1883
 
                         st.st_ino, st.st_mode)
 
1857
            st.st_ino, st.st_mode)
1884
1858
 
1885
1859
 
1886
1860
class TestPackStat(tests.TestCaseWithTransport):
1890
1864
        self.assertEqual(expected, dirstate.pack_stat(stat_value))
1891
1865
 
1892
1866
    def test_pack_stat_int(self):
1893
 
        st = _FakeStat(6859, 1172758614, 1172758617, 777, 6499538, 0o100644)
 
1867
        st = _FakeStat(6859L, 1172758614, 1172758617, 777L, 6499538L, 0100644)
1894
1868
        # Make sure that all parameters have an impact on the packed stat.
1895
 
        self.assertPackStat(b'AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
1896
 
        st.st_size = 7000
 
1869
        self.assertPackStat('AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
 
1870
        st.st_size = 7000L
1897
1871
        #                ay0 => bWE
1898
 
        self.assertPackStat(b'AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
 
1872
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1899
1873
        st.st_mtime = 1172758620
1900
1874
        #                     4FZ => 4Fx
1901
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
 
1875
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1902
1876
        st.st_ctime = 1172758630
1903
1877
        #                          uBZ => uBm
1904
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1905
 
        st.st_dev = 888
 
1878
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
 
1879
        st.st_dev = 888L
1906
1880
        #                                DCQ => DeA
1907
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
1908
 
        st.st_ino = 6499540
 
1881
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
 
1882
        st.st_ino = 6499540L
1909
1883
        #                                     LNI => LNQ
1910
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
1911
 
        st.st_mode = 0o100744
 
1884
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
 
1885
        st.st_mode = 0100744
1912
1886
        #                                          IGk => IHk
1913
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
 
1887
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
1914
1888
 
1915
1889
    def test_pack_stat_float(self):
1916
1890
        """On some platforms mtime and ctime are floats.
1918
1892
        Make sure we don't get warnings or errors, and that we ignore changes <
1919
1893
        1s
1920
1894
        """
1921
 
        st = _FakeStat(7000, 1172758614.0, 1172758617.0,
1922
 
                       777, 6499538, 0o100644)
 
1895
        st = _FakeStat(7000L, 1172758614.0, 1172758617.0,
 
1896
                       777L, 6499538L, 0100644)
1923
1897
        # These should all be the same as the integer counterparts
1924
 
        self.assertPackStat(b'AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
 
1898
        self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1925
1899
        st.st_mtime = 1172758620.0
1926
1900
        #                     FZF5 => FxF5
1927
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
 
1901
        self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1928
1902
        st.st_ctime = 1172758630.0
1929
1903
        #                          uBZ => uBm
1930
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
 
1904
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1931
1905
        # fractional seconds are discarded, so no change from above
1932
1906
        st.st_mtime = 1172758620.453
1933
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
 
1907
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1934
1908
        st.st_ctime = 1172758630.228
1935
 
        self.assertPackStat(b'AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
 
1909
        self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1936
1910
 
1937
1911
 
1938
1912
class TestBisect(TestCaseWithDirState):
2016
1990
        tree, state, expected = self.create_basic_dirstate()
2017
1991
 
2018
1992
        # Bisect should return the rows for the specified files.
2019
 
        self.assertBisect(expected, [[b'']], state, [b''])
2020
 
        self.assertBisect(expected, [[b'a']], state, [b'a'])
2021
 
        self.assertBisect(expected, [[b'b']], state, [b'b'])
2022
 
        self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2023
 
        self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2024
 
        self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2025
 
        self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2026
 
        self.assertBisect(expected, [[b'f']], state, [b'f'])
 
1993
        self.assertBisect(expected, [['']], state, [''])
 
1994
        self.assertBisect(expected, [['a']], state, ['a'])
 
1995
        self.assertBisect(expected, [['b']], state, ['b'])
 
1996
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
 
1997
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
 
1998
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
 
1999
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
 
2000
        self.assertBisect(expected, [['f']], state, ['f'])
2027
2001
 
2028
2002
    def test_bisect_multi(self):
2029
2003
        """Bisect can be used to find multiple records at the same time."""
2030
2004
        tree, state, expected = self.create_basic_dirstate()
2031
2005
        # Bisect should be capable of finding multiple entries at the same time
2032
 
        self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2033
 
                          state, [b'a', b'b', b'f'])
2034
 
        self.assertBisect(expected, [[b'f'], [b'b/d'], [b'b/d/e']],
2035
 
                          state, [b'f', b'b/d', b'b/d/e'])
2036
 
        self.assertBisect(expected, [[b'b'], [b'b-c'], [b'b/c']],
2037
 
                          state, [b'b', b'b-c', b'b/c'])
 
2006
        self.assertBisect(expected, [['a'], ['b'], ['f']],
 
2007
                          state, ['a', 'b', 'f'])
 
2008
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
 
2009
                          state, ['f', 'b/d', 'b/d/e'])
 
2010
        self.assertBisect(expected, [['b'], ['b-c'], ['b/c']],
 
2011
                          state, ['b', 'b-c', 'b/c'])
2038
2012
 
2039
2013
    def test_bisect_one_page(self):
2040
2014
        """Test bisect when there is only 1 page to read"""
2041
2015
        tree, state, expected = self.create_basic_dirstate()
2042
2016
        state._bisect_page_size = 5000
2043
 
        self.assertBisect(expected, [[b'']], state, [b''])
2044
 
        self.assertBisect(expected, [[b'a']], state, [b'a'])
2045
 
        self.assertBisect(expected, [[b'b']], state, [b'b'])
2046
 
        self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2047
 
        self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2048
 
        self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2049
 
        self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2050
 
        self.assertBisect(expected, [[b'f']], state, [b'f'])
2051
 
        self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2052
 
                          state, [b'a', b'b', b'f'])
2053
 
        self.assertBisect(expected, [[b'b/d'], [b'b/d/e'], [b'f']],
2054
 
                          state, [b'b/d', b'b/d/e', b'f'])
2055
 
        self.assertBisect(expected, [[b'b'], [b'b/c'], [b'b-c']],
2056
 
                          state, [b'b', b'b/c', b'b-c'])
 
2017
        self.assertBisect(expected,[['']], state, [''])
 
2018
        self.assertBisect(expected,[['a']], state, ['a'])
 
2019
        self.assertBisect(expected,[['b']], state, ['b'])
 
2020
        self.assertBisect(expected,[['b/c']], state, ['b/c'])
 
2021
        self.assertBisect(expected,[['b/d']], state, ['b/d'])
 
2022
        self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
 
2023
        self.assertBisect(expected,[['b-c']], state, ['b-c'])
 
2024
        self.assertBisect(expected,[['f']], state, ['f'])
 
2025
        self.assertBisect(expected,[['a'], ['b'], ['f']],
 
2026
                          state, ['a', 'b', 'f'])
 
2027
        self.assertBisect(expected, [['b/d'], ['b/d/e'], ['f']],
 
2028
                          state, ['b/d', 'b/d/e', 'f'])
 
2029
        self.assertBisect(expected, [['b'], ['b/c'], ['b-c']],
 
2030
                          state, ['b', 'b/c', 'b-c'])
2057
2031
 
2058
2032
    def test_bisect_duplicate_paths(self):
2059
2033
        """When bisecting for a path, handle multiple entries."""
2060
2034
        tree, state, expected = self.create_duplicated_dirstate()
2061
2035
 
2062
2036
        # Now make sure that both records are properly returned.
2063
 
        self.assertBisect(expected, [[b'']], state, [b''])
2064
 
        self.assertBisect(expected, [[b'a', b'a2']], state, [b'a'])
2065
 
        self.assertBisect(expected, [[b'b', b'b2']], state, [b'b'])
2066
 
        self.assertBisect(expected, [[b'b/c', b'b/c2']], state, [b'b/c'])
2067
 
        self.assertBisect(expected, [[b'b/d', b'b/d2']], state, [b'b/d'])
2068
 
        self.assertBisect(expected, [[b'b/d/e', b'b/d/e2']],
2069
 
                          state, [b'b/d/e'])
2070
 
        self.assertBisect(expected, [[b'b-c', b'b-c2']], state, [b'b-c'])
2071
 
        self.assertBisect(expected, [[b'f', b'f2']], state, [b'f'])
 
2037
        self.assertBisect(expected, [['']], state, [''])
 
2038
        self.assertBisect(expected, [['a', 'a2']], state, ['a'])
 
2039
        self.assertBisect(expected, [['b', 'b2']], state, ['b'])
 
2040
        self.assertBisect(expected, [['b/c', 'b/c2']], state, ['b/c'])
 
2041
        self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
 
2042
        self.assertBisect(expected, [['b/d/e', 'b/d/e2']],
 
2043
                          state, ['b/d/e'])
 
2044
        self.assertBisect(expected, [['b-c', 'b-c2']], state, ['b-c'])
 
2045
        self.assertBisect(expected, [['f', 'f2']], state, ['f'])
2072
2046
 
2073
2047
    def test_bisect_page_size_too_small(self):
2074
2048
        """If the page size is too small, we will auto increase it."""
2075
2049
        tree, state, expected = self.create_basic_dirstate()
2076
2050
        state._bisect_page_size = 50
2077
 
        self.assertBisect(expected, [None], state, [b'b/e'])
2078
 
        self.assertBisect(expected, [[b'a']], state, [b'a'])
2079
 
        self.assertBisect(expected, [[b'b']], state, [b'b'])
2080
 
        self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2081
 
        self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2082
 
        self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2083
 
        self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2084
 
        self.assertBisect(expected, [[b'f']], state, [b'f'])
 
2051
        self.assertBisect(expected, [None], state, ['b/e'])
 
2052
        self.assertBisect(expected, [['a']], state, ['a'])
 
2053
        self.assertBisect(expected, [['b']], state, ['b'])
 
2054
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
 
2055
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
 
2056
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
 
2057
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
 
2058
        self.assertBisect(expected, [['f']], state, ['f'])
2085
2059
 
2086
2060
    def test_bisect_missing(self):
2087
2061
        """Test that bisect return None if it cannot find a path."""
2088
2062
        tree, state, expected = self.create_basic_dirstate()
2089
 
        self.assertBisect(expected, [None], state, [b'foo'])
2090
 
        self.assertBisect(expected, [None], state, [b'b/foo'])
2091
 
        self.assertBisect(expected, [None], state, [b'bar/foo'])
2092
 
        self.assertBisect(expected, [None], state, [b'b-c/foo'])
 
2063
        self.assertBisect(expected, [None], state, ['foo'])
 
2064
        self.assertBisect(expected, [None], state, ['b/foo'])
 
2065
        self.assertBisect(expected, [None], state, ['bar/foo'])
 
2066
        self.assertBisect(expected, [None], state, ['b-c/foo'])
2093
2067
 
2094
 
        self.assertBisect(expected, [[b'a'], None, [b'b/d']],
2095
 
                          state, [b'a', b'foo', b'b/d'])
 
2068
        self.assertBisect(expected, [['a'], None, ['b/d']],
 
2069
                          state, ['a', 'foo', 'b/d'])
2096
2070
 
2097
2071
    def test_bisect_rename(self):
2098
2072
        """Check that we find a renamed row."""
2099
2073
        tree, state, expected = self.create_renamed_dirstate()
2100
2074
 
2101
2075
        # Search for the pre and post renamed entries
2102
 
        self.assertBisect(expected, [[b'a']], state, [b'a'])
2103
 
        self.assertBisect(expected, [[b'b/g']], state, [b'b/g'])
2104
 
        self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2105
 
        self.assertBisect(expected, [[b'h']], state, [b'h'])
 
2076
        self.assertBisect(expected, [['a']], state, ['a'])
 
2077
        self.assertBisect(expected, [['b/g']], state, ['b/g'])
 
2078
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
 
2079
        self.assertBisect(expected, [['h']], state, ['h'])
2106
2080
 
2107
2081
        # What about b/d/e? shouldn't that also get 2 directory entries?
2108
 
        self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2109
 
        self.assertBisect(expected, [[b'h/e']], state, [b'h/e'])
 
2082
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
 
2083
        self.assertBisect(expected, [['h/e']], state, ['h/e'])
2110
2084
 
2111
2085
    def test_bisect_dirblocks(self):
2112
2086
        tree, state, expected = self.create_duplicated_dirstate()
2113
2087
        self.assertBisectDirBlocks(expected,
2114
 
                                   [[b'', b'a', b'a2', b'b', b'b2',
2115
 
                                       b'b-c', b'b-c2', b'f', b'f2']],
2116
 
                                   state, [b''])
2117
 
        self.assertBisectDirBlocks(expected,
2118
 
                                   [[b'b/c', b'b/c2', b'b/d', b'b/d2']], state, [b'b'])
2119
 
        self.assertBisectDirBlocks(expected,
2120
 
                                   [[b'b/d/e', b'b/d/e2']], state, [b'b/d'])
2121
 
        self.assertBisectDirBlocks(expected,
2122
 
                                   [[b'', b'a', b'a2', b'b', b'b2', b'b-c', b'b-c2', b'f', b'f2'],
2123
 
                                    [b'b/c', b'b/c2', b'b/d', b'b/d2'],
2124
 
                                       [b'b/d/e', b'b/d/e2'],
2125
 
                                    ], state, [b'', b'b', b'b/d'])
 
2088
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2']],
 
2089
            state, [''])
 
2090
        self.assertBisectDirBlocks(expected,
 
2091
            [['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
 
2092
        self.assertBisectDirBlocks(expected,
 
2093
            [['b/d/e', 'b/d/e2']], state, ['b/d'])
 
2094
        self.assertBisectDirBlocks(expected,
 
2095
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2'],
 
2096
             ['b/c', 'b/c2', 'b/d', 'b/d2'],
 
2097
             ['b/d/e', 'b/d/e2'],
 
2098
            ], state, ['', 'b', 'b/d'])
2126
2099
 
2127
2100
    def test_bisect_dirblocks_missing(self):
2128
2101
        tree, state, expected = self.create_basic_dirstate()
2129
 
        self.assertBisectDirBlocks(expected, [[b'b/d/e'], None],
2130
 
                                   state, [b'b/d', b'b/e'])
 
2102
        self.assertBisectDirBlocks(expected, [['b/d/e'], None],
 
2103
            state, ['b/d', 'b/e'])
2131
2104
        # Files don't show up in this search
2132
 
        self.assertBisectDirBlocks(expected, [None], state, [b'a'])
2133
 
        self.assertBisectDirBlocks(expected, [None], state, [b'b/c'])
2134
 
        self.assertBisectDirBlocks(expected, [None], state, [b'c'])
2135
 
        self.assertBisectDirBlocks(expected, [None], state, [b'b/d/e'])
2136
 
        self.assertBisectDirBlocks(expected, [None], state, [b'f'])
 
2105
        self.assertBisectDirBlocks(expected, [None], state, ['a'])
 
2106
        self.assertBisectDirBlocks(expected, [None], state, ['b/c'])
 
2107
        self.assertBisectDirBlocks(expected, [None], state, ['c'])
 
2108
        self.assertBisectDirBlocks(expected, [None], state, ['b/d/e'])
 
2109
        self.assertBisectDirBlocks(expected, [None], state, ['f'])
2137
2110
 
2138
2111
    def test_bisect_recursive_each(self):
2139
2112
        tree, state, expected = self.create_basic_dirstate()
2140
 
        self.assertBisectRecursive(expected, [b'a'], state, [b'a'])
2141
 
        self.assertBisectRecursive(expected, [b'b/c'], state, [b'b/c'])
2142
 
        self.assertBisectRecursive(expected, [b'b/d/e'], state, [b'b/d/e'])
2143
 
        self.assertBisectRecursive(expected, [b'b-c'], state, [b'b-c'])
2144
 
        self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2145
 
                                   state, [b'b/d'])
2146
 
        self.assertBisectRecursive(expected, [b'b', b'b/c', b'b/d', b'b/d/e'],
2147
 
                                   state, [b'b'])
2148
 
        self.assertBisectRecursive(expected, [b'', b'a', b'b', b'b-c', b'f', b'b/c',
2149
 
                                              b'b/d', b'b/d/e'],
2150
 
                                   state, [b''])
 
2113
        self.assertBisectRecursive(expected, ['a'], state, ['a'])
 
2114
        self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
 
2115
        self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
 
2116
        self.assertBisectRecursive(expected, ['b-c'], state, ['b-c'])
 
2117
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
 
2118
                                   state, ['b/d'])
 
2119
        self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
 
2120
                                   state, ['b'])
 
2121
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'b-c', 'f', 'b/c',
 
2122
                                              'b/d', 'b/d/e'],
 
2123
                                   state, [''])
2151
2124
 
2152
2125
    def test_bisect_recursive_multiple(self):
2153
2126
        tree, state, expected = self.create_basic_dirstate()
2154
 
        self.assertBisectRecursive(
2155
 
            expected, [b'a', b'b/c'], state, [b'a', b'b/c'])
2156
 
        self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2157
 
                                   state, [b'b/d', b'b/d/e'])
 
2127
        self.assertBisectRecursive(expected, ['a', 'b/c'], state, ['a', 'b/c'])
 
2128
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
 
2129
                                   state, ['b/d', 'b/d/e'])
2158
2130
 
2159
2131
    def test_bisect_recursive_missing(self):
2160
2132
        tree, state, expected = self.create_basic_dirstate()
2161
 
        self.assertBisectRecursive(expected, [], state, [b'd'])
2162
 
        self.assertBisectRecursive(expected, [], state, [b'b/e'])
2163
 
        self.assertBisectRecursive(expected, [], state, [b'g'])
2164
 
        self.assertBisectRecursive(expected, [b'a'], state, [b'a', b'g'])
 
2133
        self.assertBisectRecursive(expected, [], state, ['d'])
 
2134
        self.assertBisectRecursive(expected, [], state, ['b/e'])
 
2135
        self.assertBisectRecursive(expected, [], state, ['g'])
 
2136
        self.assertBisectRecursive(expected, ['a'], state, ['a', 'g'])
2165
2137
 
2166
2138
    def test_bisect_recursive_renamed(self):
2167
2139
        tree, state, expected = self.create_renamed_dirstate()
2168
2140
 
2169
2141
        # Looking for either renamed item should find the other
2170
 
        self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'a'])
2171
 
        self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'b/g'])
 
2142
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
 
2143
        self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
2172
2144
        # Looking in the containing directory should find the rename target,
2173
2145
        # and anything in a subdir of the renamed target.
2174
 
        self.assertBisectRecursive(expected, [b'a', b'b', b'b/c', b'b/d',
2175
 
                                              b'b/d/e', b'b/g', b'h', b'h/e'],
2176
 
                                   state, [b'b'])
 
2146
        self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
 
2147
                                              'b/d/e', 'b/g', 'h', 'h/e'],
 
2148
                                   state, ['b'])
2177
2149
 
2178
2150
 
2179
2151
class TestDirstateValidation(TestCaseWithDirState):
2196
2168
        # we're appending to the dirblock, but this name comes before some of
2197
2169
        # the existing names; that's wrong
2198
2170
        last_dirblock[1].append(
2199
 
            ((b'h', b'aaaa', b'a-id'),
2200
 
             [(b'a', b'', 0, False, b''),
2201
 
              (b'a', b'', 0, False, b'')]))
 
2171
            (('h', 'aaaa', 'a-id'),
 
2172
             [('a', '', 0, False, ''),
 
2173
              ('a', '', 0, False, '')]))
2202
2174
        e = self.assertRaises(AssertionError,
2203
 
                              state._validate)
 
2175
            state._validate)
2204
2176
        self.assertContainsRe(str(e), 'not sorted')
2205
2177
 
2206
2178
    def test_dirblock_name_mismatch(self):
2209
2181
        last_dirblock = state._dirblocks[-1]
2210
2182
        # add an entry with the wrong directory name
2211
2183
        last_dirblock[1].append(
2212
 
            ((b'', b'z', b'a-id'),
2213
 
             [(b'a', b'', 0, False, b''),
2214
 
              (b'a', b'', 0, False, b'')]))
 
2184
            (('', 'z', 'a-id'),
 
2185
             [('a', '', 0, False, ''),
 
2186
              ('a', '', 0, False, '')]))
2215
2187
        e = self.assertRaises(AssertionError,
2216
 
                              state._validate)
 
2188
            state._validate)
2217
2189
        self.assertContainsRe(str(e),
2218
 
                              "doesn't match directory name")
 
2190
            "doesn't match directory name")
2219
2191
 
2220
2192
    def test_dirblock_missing_rename(self):
2221
2193
        tree, state, expected = self.create_renamed_dirstate()
2224
2196
        # make another entry for a-id, without a correct 'r' pointer to
2225
2197
        # the real occurrence in the working tree
2226
2198
        last_dirblock[1].append(
2227
 
            ((b'h', b'z', b'a-id'),
2228
 
             [(b'a', b'', 0, False, b''),
2229
 
              (b'a', b'', 0, False, b'')]))
 
2199
            (('h', 'z', 'a-id'),
 
2200
             [('a', '', 0, False, ''),
 
2201
              ('a', '', 0, False, '')]))
2230
2202
        e = self.assertRaises(AssertionError,
2231
 
                              state._validate)
 
2203
            state._validate)
2232
2204
        self.assertContainsRe(str(e),
2233
 
                              'file a-id is absent in row')
 
2205
            'file a-id is absent in row')
2234
2206
 
2235
2207
 
2236
2208
class TestDirstateTreeReference(TestCaseWithDirState):
2238
2210
    def test_reference_revision_is_none(self):
2239
2211
        tree = self.make_branch_and_tree('tree', format='development-subtree')
2240
2212
        subtree = self.make_branch_and_tree('tree/subtree',
2241
 
                                            format='development-subtree')
2242
 
        subtree.set_root_id(b'subtree')
 
2213
                            format='development-subtree')
 
2214
        subtree.set_root_id('subtree')
2243
2215
        tree.add_reference(subtree)
2244
2216
        tree.add('subtree')
2245
2217
        state = dirstate.DirState.from_tree(tree, 'dirstate')
2246
 
        key = (b'', b'subtree', b'subtree')
2247
 
        expected = (b'', [(key,
2248
 
                           [(b't', b'', 0, False, b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])])
 
2218
        key = ('', 'subtree', 'subtree')
 
2219
        expected = ('', [(key,
 
2220
            [('t', '', 0, False, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])])
2249
2221
 
2250
2222
        try:
2251
2223
            self.assertEqual(expected, state._find_block(key))
2264
2236
 
2265
2237
    def test_discard_one_parent(self):
2266
2238
        # No-op
2267
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2268
 
        root_entry_direntry = (b'', b'', b'a-root-value'), [
2269
 
            (b'd', b'', 0, False, packed_stat),
2270
 
            (b'd', b'', 0, False, packed_stat),
 
2239
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
2240
        root_entry_direntry = ('', '', 'a-root-value'), [
 
2241
            ('d', '', 0, False, packed_stat),
 
2242
            ('d', '', 0, False, packed_stat),
2271
2243
            ]
2272
2244
        dirblocks = []
2273
 
        dirblocks.append((b'', [root_entry_direntry]))
2274
 
        dirblocks.append((b'', []))
 
2245
        dirblocks.append(('', [root_entry_direntry]))
 
2246
        dirblocks.append(('', []))
2275
2247
 
2276
2248
        state = self.create_empty_dirstate()
2277
2249
        self.addCleanup(state.unlock)
2278
 
        state._set_data([b'parent-id'], dirblocks[:])
 
2250
        state._set_data(['parent-id'], dirblocks[:])
2279
2251
        state._validate()
2280
2252
 
2281
2253
        state._discard_merge_parents()
2284
2256
 
2285
2257
    def test_discard_simple(self):
2286
2258
        # No-op
2287
 
        packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2288
 
        root_entry_direntry = (b'', b'', b'a-root-value'), [
2289
 
            (b'd', b'', 0, False, packed_stat),
2290
 
            (b'd', b'', 0, False, packed_stat),
2291
 
            (b'd', b'', 0, False, packed_stat),
 
2259
        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
 
2260
        root_entry_direntry = ('', '', 'a-root-value'), [
 
2261
            ('d', '', 0, False, packed_stat),
 
2262
            ('d', '', 0, False, packed_stat),
 
2263
            ('d', '', 0, False, packed_stat),
2292
2264
            ]
2293
 
        expected_root_entry_direntry = (b'', b'', b'a-root-value'), [
2294
 
            (b'd', b'', 0, False, packed_stat),
2295
 
            (b'd', b'', 0, False, packed_stat),
 
2265
        expected_root_entry_direntry = ('', '', 'a-root-value'), [
 
2266
            ('d', '', 0, False, packed_stat),
 
2267
            ('d', '', 0, False, packed_stat),
2296
2268
            ]
2297
2269
        dirblocks = []
2298
 
        dirblocks.append((b'', [root_entry_direntry]))
2299
 
        dirblocks.append((b'', []))
 
2270
        dirblocks.append(('', [root_entry_direntry]))
 
2271
        dirblocks.append(('', []))
2300
2272
 
2301
2273
        state = self.create_empty_dirstate()
2302
2274
        self.addCleanup(state.unlock)
2303
 
        state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
 
2275
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2304
2276
        state._validate()
2305
2277
 
2306
2278
        # This should strip of the extra column
2307
2279
        state._discard_merge_parents()
2308
2280
        state._validate()
2309
 
        expected_dirblocks = [(b'', [expected_root_entry_direntry]), (b'', [])]
 
2281
        expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2310
2282
        self.assertEqual(expected_dirblocks, state._dirblocks)
2311
2283
 
2312
2284
    def test_discard_absent(self):
2313
2285
        """If entries are only in a merge, discard should remove the entries"""
2314
2286
        null_stat = dirstate.DirState.NULLSTAT
2315
 
        present_dir = (b'd', b'', 0, False, null_stat)
2316
 
        present_file = (b'f', b'', 0, False, null_stat)
 
2287
        present_dir = ('d', '', 0, False, null_stat)
 
2288
        present_file = ('f', '', 0, False, null_stat)
2317
2289
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2318
 
        root_key = (b'', b'', b'a-root-value')
2319
 
        file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2320
 
        file_in_merged_key = (b'', b'file-in-merged', b'b-file-id')
2321
 
        dirblocks = [(b'', [(root_key, [present_dir, present_dir, present_dir])]),
2322
 
                     (b'', [(file_in_merged_key,
2323
 
                             [absent, absent, present_file]),
2324
 
                            (file_in_root_key,
2325
 
                             [present_file, present_file, present_file]),
2326
 
                            ]),
2327
 
                     ]
 
2290
        root_key = ('', '', 'a-root-value')
 
2291
        file_in_root_key = ('', 'file-in-root', 'a-file-id')
 
2292
        file_in_merged_key = ('', 'file-in-merged', 'b-file-id')
 
2293
        dirblocks = [('', [(root_key, [present_dir, present_dir, present_dir])]),
 
2294
                     ('', [(file_in_merged_key,
 
2295
                            [absent, absent, present_file]),
 
2296
                           (file_in_root_key,
 
2297
                            [present_file, present_file, present_file]),
 
2298
                          ]),
 
2299
                    ]
2328
2300
 
2329
2301
        state = self.create_empty_dirstate()
2330
2302
        self.addCleanup(state.unlock)
2331
 
        state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
 
2303
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2332
2304
        state._validate()
2333
2305
 
2334
 
        exp_dirblocks = [(b'', [(root_key, [present_dir, present_dir])]),
2335
 
                         (b'', [(file_in_root_key,
2336
 
                                 [present_file, present_file]),
2337
 
                                ]),
2338
 
                         ]
 
2306
        exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
 
2307
                         ('', [(file_in_root_key,
 
2308
                                [present_file, present_file]),
 
2309
                              ]),
 
2310
                        ]
2339
2311
        state._discard_merge_parents()
2340
2312
        state._validate()
2341
2313
        self.assertEqual(exp_dirblocks, state._dirblocks)
2342
2314
 
2343
2315
    def test_discard_renamed(self):
2344
2316
        null_stat = dirstate.DirState.NULLSTAT
2345
 
        present_dir = (b'd', b'', 0, False, null_stat)
2346
 
        present_file = (b'f', b'', 0, False, null_stat)
 
2317
        present_dir = ('d', '', 0, False, null_stat)
 
2318
        present_file = ('f', '', 0, False, null_stat)
2347
2319
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2348
 
        root_key = (b'', b'', b'a-root-value')
2349
 
        file_in_root_key = (b'', b'file-in-root', b'a-file-id')
 
2320
        root_key = ('', '', 'a-root-value')
 
2321
        file_in_root_key = ('', 'file-in-root', 'a-file-id')
2350
2322
        # Renamed relative to parent
2351
 
        file_rename_s_key = (b'', b'file-s', b'b-file-id')
2352
 
        file_rename_t_key = (b'', b'file-t', b'b-file-id')
 
2323
        file_rename_s_key = ('', 'file-s', 'b-file-id')
 
2324
        file_rename_t_key = ('', 'file-t', 'b-file-id')
2353
2325
        # And one that is renamed between the parents, but absent in this
2354
 
        key_in_1 = (b'', b'file-in-1', b'c-file-id')
2355
 
        key_in_2 = (b'', b'file-in-2', b'c-file-id')
 
2326
        key_in_1 = ('', 'file-in-1', 'c-file-id')
 
2327
        key_in_2 = ('', 'file-in-2', 'c-file-id')
2356
2328
 
2357
2329
        dirblocks = [
2358
 
            (b'', [(root_key, [present_dir, present_dir, present_dir])]),
2359
 
            (b'', [(key_in_1,
2360
 
                    [absent, present_file, (b'r', b'file-in-2', b'c-file-id')]),
2361
 
                   (key_in_2,
2362
 
                    [absent, (b'r', b'file-in-1', b'c-file-id'), present_file]),
2363
 
                   (file_in_root_key,
2364
 
                    [present_file, present_file, present_file]),
2365
 
                   (file_rename_s_key,
2366
 
                    [(b'r', b'file-t', b'b-file-id'), absent, present_file]),
2367
 
                   (file_rename_t_key,
2368
 
                    [present_file, absent, (b'r', b'file-s', b'b-file-id')]),
2369
 
                   ]),
 
2330
            ('', [(root_key, [present_dir, present_dir, present_dir])]),
 
2331
            ('', [(key_in_1,
 
2332
                   [absent, present_file, ('r', 'file-in-2', 'c-file-id')]),
 
2333
                  (key_in_2,
 
2334
                   [absent, ('r', 'file-in-1', 'c-file-id'), present_file]),
 
2335
                  (file_in_root_key,
 
2336
                   [present_file, present_file, present_file]),
 
2337
                  (file_rename_s_key,
 
2338
                   [('r', 'file-t', 'b-file-id'), absent, present_file]),
 
2339
                  (file_rename_t_key,
 
2340
                   [present_file, absent, ('r', 'file-s', 'b-file-id')]),
 
2341
                 ]),
2370
2342
        ]
2371
2343
        exp_dirblocks = [
2372
 
            (b'', [(root_key, [present_dir, present_dir])]),
2373
 
            (b'', [(key_in_1, [absent, present_file]),
2374
 
                   (file_in_root_key, [present_file, present_file]),
2375
 
                   (file_rename_t_key, [present_file, absent]),
2376
 
                   ]),
 
2344
            ('', [(root_key, [present_dir, present_dir])]),
 
2345
            ('', [(key_in_1, [absent, present_file]),
 
2346
                  (file_in_root_key, [present_file, present_file]),
 
2347
                  (file_rename_t_key, [present_file, absent]),
 
2348
                 ]),
2377
2349
        ]
2378
2350
        state = self.create_empty_dirstate()
2379
2351
        self.addCleanup(state.unlock)
2380
 
        state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
 
2352
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2381
2353
        state._validate()
2382
2354
 
2383
2355
        state._discard_merge_parents()
2386
2358
 
2387
2359
    def test_discard_all_subdir(self):
2388
2360
        null_stat = dirstate.DirState.NULLSTAT
2389
 
        present_dir = (b'd', b'', 0, False, null_stat)
2390
 
        present_file = (b'f', b'', 0, False, null_stat)
 
2361
        present_dir = ('d', '', 0, False, null_stat)
 
2362
        present_file = ('f', '', 0, False, null_stat)
2391
2363
        absent = dirstate.DirState.NULL_PARENT_DETAILS
2392
 
        root_key = (b'', b'', b'a-root-value')
2393
 
        subdir_key = (b'', b'sub', b'dir-id')
2394
 
        child1_key = (b'sub', b'child1', b'child1-id')
2395
 
        child2_key = (b'sub', b'child2', b'child2-id')
2396
 
        child3_key = (b'sub', b'child3', b'child3-id')
 
2364
        root_key = ('', '', 'a-root-value')
 
2365
        subdir_key = ('', 'sub', 'dir-id')
 
2366
        child1_key = ('sub', 'child1', 'child1-id')
 
2367
        child2_key = ('sub', 'child2', 'child2-id')
 
2368
        child3_key = ('sub', 'child3', 'child3-id')
2397
2369
 
2398
2370
        dirblocks = [
2399
 
            (b'', [(root_key, [present_dir, present_dir, present_dir])]),
2400
 
            (b'', [(subdir_key, [present_dir, present_dir, present_dir])]),
2401
 
            (b'sub', [(child1_key, [absent, absent, present_file]),
2402
 
                      (child2_key, [absent, absent, present_file]),
2403
 
                      (child3_key, [absent, absent, present_file]),
2404
 
                      ]),
 
2371
            ('', [(root_key, [present_dir, present_dir, present_dir])]),
 
2372
            ('', [(subdir_key, [present_dir, present_dir, present_dir])]),
 
2373
            ('sub', [(child1_key, [absent, absent, present_file]),
 
2374
                     (child2_key, [absent, absent, present_file]),
 
2375
                     (child3_key, [absent, absent, present_file]),
 
2376
                    ]),
2405
2377
        ]
2406
2378
        exp_dirblocks = [
2407
 
            (b'', [(root_key, [present_dir, present_dir])]),
2408
 
            (b'', [(subdir_key, [present_dir, present_dir])]),
2409
 
            (b'sub', []),
 
2379
            ('', [(root_key, [present_dir, present_dir])]),
 
2380
            ('', [(subdir_key, [present_dir, present_dir])]),
 
2381
            ('sub', []),
2410
2382
        ]
2411
2383
        state = self.create_empty_dirstate()
2412
2384
        self.addCleanup(state.unlock)
2413
 
        state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
 
2385
        state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2414
2386
        state._validate()
2415
2387
 
2416
2388
        state._discard_merge_parents()
2426
2398
        # details should always allow join() and always be a plain str when
2427
2399
        # finished
2428
2400
        (minikind, fingerprint, size, executable, tree_data) = details
2429
 
        self.assertIsInstance(minikind, bytes)
2430
 
        self.assertIsInstance(fingerprint, bytes)
2431
 
        self.assertIsInstance(tree_data, bytes)
 
2401
        self.assertIsInstance(minikind, str)
 
2402
        self.assertIsInstance(fingerprint, str)
 
2403
        self.assertIsInstance(tree_data, str)
2432
2404
 
2433
2405
    def test_unicode_symlink(self):
2434
 
        inv_entry = inventory.InventoryLink(b'link-file-id',
 
2406
        inv_entry = inventory.InventoryLink('link-file-id',
2435
2407
                                            u'nam\N{Euro Sign}e',
2436
 
                                            b'link-parent-id')
2437
 
        inv_entry.revision = b'link-revision-id'
 
2408
                                            'link-parent-id')
 
2409
        inv_entry.revision = 'link-revision-id'
2438
2410
        target = u'link-targ\N{Euro Sign}t'
2439
2411
        inv_entry.symlink_target = target
2440
 
        self.assertDetails((b'l', target.encode('UTF-8'), 0, False,
2441
 
                            b'link-revision-id'), inv_entry)
 
2412
        self.assertDetails(('l', target.encode('UTF-8'), 0, False,
 
2413
                            'link-revision-id'), inv_entry)
2442
2414
 
2443
2415
 
2444
2416
class TestSHA1Provider(tests.TestCaseInTempDir):
2449
2421
        self.assertRaises(NotImplementedError, p.stat_and_sha1, "foo")
2450
2422
 
2451
2423
    def test_defaultsha1provider_sha1(self):
2452
 
        text = b'test\r\nwith\nall\rpossible line endings\r\n'
 
2424
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
2453
2425
        self.build_tree_contents([('foo', text)])
2454
2426
        expected_sha = osutils.sha_string(text)
2455
2427
        p = dirstate.DefaultSHA1Provider()
2456
2428
        self.assertEqual(expected_sha, p.sha1('foo'))
2457
2429
 
2458
2430
    def test_defaultsha1provider_stat_and_sha1(self):
2459
 
        text = b'test\r\nwith\nall\rpossible line endings\r\n'
 
2431
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
2460
2432
        self.build_tree_contents([('foo', text)])
2461
2433
        expected_sha = osutils.sha_string(text)
2462
2434
        p = dirstate.DefaultSHA1Provider()
2470
2442
    """A minimal api to get InventoryRevisionTree to work."""
2471
2443
 
2472
2444
    def __init__(self):
2473
 
        default_format = controldir.format_registry.make_controldir('default')
 
2445
        default_format = controldir.format_registry.make_bzrdir('default')
2474
2446
        self._format = default_format.repository_format
2475
2447
 
2476
2448
    def lock_read(self):
2492
2464
        try:
2493
2465
            dir_id = dir_ids[dirname]
2494
2466
        except KeyError:
2495
 
            dir_id = osutils.basename(dirname).encode('utf-8') + b'-id'
 
2467
            dir_id = osutils.basename(dirname) + '-id'
2496
2468
        if is_dir:
2497
2469
            ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2498
2470
            dir_ids[path] = file_id
2499
2471
        else:
2500
2472
            ie = inventory.InventoryFile(file_id, basename, dir_id)
2501
2473
            ie.text_size = 0
2502
 
            ie.text_sha1 = b''
 
2474
            ie.text_sha1 = ''
2503
2475
        ie.revision = rev_id
2504
2476
        return ie
2505
2477
 
2506
2478
    def create_tree_from_shape(self, rev_id, shape):
2507
 
        dir_ids = {'': b'root-id'}
2508
 
        inv = inventory.Inventory(b'root-id', rev_id)
 
2479
        dir_ids = {'': 'root-id'}
 
2480
        inv = inventory.Inventory('root-id', rev_id)
2509
2481
        for info in shape:
2510
2482
            if len(info) == 2:
2511
2483
                path, file_id = info
2520
2492
                dir_ids[''] = file_id
2521
2493
                continue
2522
2494
            inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2523
 
        return inventorytree.InventoryRevisionTree(_Repo(), inv, rev_id)
 
2495
        return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2524
2496
 
2525
2497
    def create_empty_dirstate(self):
2526
2498
        fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2532
2504
 
2533
2505
    def create_inv_delta(self, delta, rev_id):
2534
2506
        """Translate a 'delta shape' into an actual InventoryDelta"""
2535
 
        dir_ids = {'': b'root-id'}
 
2507
        dir_ids = {'': 'root-id'}
2536
2508
        inv_delta = []
2537
2509
        for old_path, new_path, file_id in delta:
2538
2510
            if old_path is not None and old_path.endswith('/'):
2539
2511
                # Don't have to actually do anything for this, because only
2540
2512
                # new_path creates InventoryEntries
2541
2513
                old_path = old_path[:-1]
2542
 
            if new_path is None:  # Delete
 
2514
            if new_path is None: # Delete
2543
2515
                inv_delta.append((old_path, None, file_id, None))
2544
2516
                continue
2545
2517
            ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2554
2526
        and assert that the DirState is still valid, and that its stored
2555
2527
        content matches the target_shape.
2556
2528
        """
2557
 
        active_tree = self.create_tree_from_shape(b'active', active)
2558
 
        basis_tree = self.create_tree_from_shape(b'basis', basis)
2559
 
        target_tree = self.create_tree_from_shape(b'target', target)
 
2529
        active_tree = self.create_tree_from_shape('active', active)
 
2530
        basis_tree = self.create_tree_from_shape('basis', basis)
 
2531
        target_tree = self.create_tree_from_shape('target', target)
2560
2532
        state = self.create_empty_dirstate()
2561
2533
        state.set_state_from_scratch(active_tree.root_inventory,
2562
 
                                     [(b'basis', basis_tree)], [])
 
2534
            [('basis', basis_tree)], [])
2563
2535
        delta = target_tree.root_inventory._make_delta(
2564
2536
            basis_tree.root_inventory)
2565
 
        state.update_basis_by_delta(delta, b'target')
 
2537
        state.update_basis_by_delta(delta, 'target')
2566
2538
        state._validate()
2567
 
        dirstate_tree = workingtree_4.DirStateRevisionTree(
2568
 
            state, b'target', _Repo(), None)
 
2539
        dirstate_tree = workingtree_4.DirStateRevisionTree(state,
 
2540
            'target', _Repo())
2569
2541
        # The target now that delta has been applied should match the
2570
2542
        # RevisionTree
2571
2543
        self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2573
2545
        # it from scratch.
2574
2546
        state2 = self.create_empty_dirstate()
2575
2547
        state2.set_state_from_scratch(active_tree.root_inventory,
2576
 
                                      [(b'target', target_tree)], [])
 
2548
            [('target', target_tree)], [])
2577
2549
        self.assertEqual(state2._dirblocks, state._dirblocks)
2578
2550
        return state
2579
2551
 
2584
2556
        :param basis: The basis tree shape
2585
2557
        :param delta: A description of the delta to apply. Similar to the form
2586
2558
            for regular inventory deltas, but omitting the InventoryEntry.
2587
 
            So adding a file is: (None, 'path', b'file-id')
2588
 
            Adding a directory is: (None, 'path/', b'dir-id')
2589
 
            Renaming a dir is: ('old/', 'new/', b'dir-id')
 
2559
            So adding a file is: (None, 'path', 'file-id')
 
2560
            Adding a directory is: (None, 'path/', 'dir-id')
 
2561
            Renaming a dir is: ('old/', 'new/', 'dir-id')
2590
2562
            etc.
2591
2563
        """
2592
 
        active_tree = self.create_tree_from_shape(b'active', active)
2593
 
        basis_tree = self.create_tree_from_shape(b'basis', basis)
2594
 
        inv_delta = self.create_inv_delta(delta, b'target')
 
2564
        active_tree = self.create_tree_from_shape('active', active)
 
2565
        basis_tree = self.create_tree_from_shape('basis', basis)
 
2566
        inv_delta = self.create_inv_delta(delta, 'target')
2595
2567
        state = self.create_empty_dirstate()
2596
2568
        state.set_state_from_scratch(active_tree.root_inventory,
2597
 
                                     [(b'basis', basis_tree)], [])
 
2569
            [('basis', basis_tree)], [])
2598
2570
        self.assertRaises(errors.InconsistentDelta,
2599
 
                          state.update_basis_by_delta, inv_delta, b'target')
2600
 
        # try:
2601
 
        ##     state.update_basis_by_delta(inv_delta, b'target')
2602
 
        # except errors.InconsistentDelta, e:
 
2571
            state.update_basis_by_delta, inv_delta, 'target')
 
2572
        ## try:
 
2573
        ##     state.update_basis_by_delta(inv_delta, 'target')
 
2574
        ## except errors.InconsistentDelta, e:
2603
2575
        ##     import pdb; pdb.set_trace()
2604
 
        # else:
 
2576
        ## else:
2605
2577
        ##     import pdb; pdb.set_trace()
2606
2578
        self.assertTrue(state._changes_aborted)
2607
2579
 
2608
2580
    def test_remove_file_matching_active_state(self):
2609
2581
        state = self.assertUpdate(
2610
2582
            active=[],
2611
 
            basis=[('file', b'file-id')],
 
2583
            basis =[('file', 'file-id')],
2612
2584
            target=[],
2613
2585
            )
2614
2586
 
2615
2587
    def test_remove_file_present_in_active_state(self):
2616
2588
        state = self.assertUpdate(
2617
 
            active=[('file', b'file-id')],
2618
 
            basis=[('file', b'file-id')],
 
2589
            active=[('file', 'file-id')],
 
2590
            basis =[('file', 'file-id')],
2619
2591
            target=[],
2620
2592
            )
2621
2593
 
2622
2594
    def test_remove_file_present_elsewhere_in_active_state(self):
2623
2595
        state = self.assertUpdate(
2624
 
            active=[('other-file', b'file-id')],
2625
 
            basis=[('file', b'file-id')],
 
2596
            active=[('other-file', 'file-id')],
 
2597
            basis =[('file', 'file-id')],
2626
2598
            target=[],
2627
2599
            )
2628
2600
 
2629
2601
    def test_remove_file_active_state_has_diff_file(self):
2630
2602
        state = self.assertUpdate(
2631
 
            active=[('file', b'file-id-2')],
2632
 
            basis=[('file', b'file-id')],
 
2603
            active=[('file', 'file-id-2')],
 
2604
            basis =[('file', 'file-id')],
2633
2605
            target=[],
2634
2606
            )
2635
2607
 
2636
2608
    def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2637
2609
        state = self.assertUpdate(
2638
 
            active=[('file', b'file-id-2'),
2639
 
                    ('other-file', b'file-id')],
2640
 
            basis=[('file', b'file-id')],
 
2610
            active=[('file', 'file-id-2'),
 
2611
                    ('other-file', 'file-id')],
 
2612
            basis =[('file', 'file-id')],
2641
2613
            target=[],
2642
2614
            )
2643
2615
 
2644
2616
    def test_add_file_matching_active_state(self):
2645
2617
        state = self.assertUpdate(
2646
 
            active=[('file', b'file-id')],
2647
 
            basis=[],
2648
 
            target=[('file', b'file-id')],
 
2618
            active=[('file', 'file-id')],
 
2619
            basis =[],
 
2620
            target=[('file', 'file-id')],
2649
2621
            )
2650
2622
 
2651
2623
    def test_add_file_in_empty_dir_not_matching_active_state(self):
2652
2624
        state = self.assertUpdate(
2653
 
            active=[],
2654
 
            basis=[('dir/', b'dir-id')],
2655
 
            target=[('dir/', b'dir-id', b'basis'), ('dir/file', b'file-id')],
2656
 
            )
 
2625
                active=[],
 
2626
                basis=[('dir/', 'dir-id')],
 
2627
                target=[('dir/', 'dir-id', 'basis'), ('dir/file', 'file-id')],
 
2628
                )
2657
2629
 
2658
2630
    def test_add_file_missing_in_active_state(self):
2659
2631
        state = self.assertUpdate(
2660
2632
            active=[],
2661
 
            basis=[],
2662
 
            target=[('file', b'file-id')],
 
2633
            basis =[],
 
2634
            target=[('file', 'file-id')],
2663
2635
            )
2664
2636
 
2665
2637
    def test_add_file_elsewhere_in_active_state(self):
2666
2638
        state = self.assertUpdate(
2667
 
            active=[('other-file', b'file-id')],
2668
 
            basis=[],
2669
 
            target=[('file', b'file-id')],
 
2639
            active=[('other-file', 'file-id')],
 
2640
            basis =[],
 
2641
            target=[('file', 'file-id')],
2670
2642
            )
2671
2643
 
2672
2644
    def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2673
2645
        state = self.assertUpdate(
2674
 
            active=[('other-file', b'file-id'),
2675
 
                    ('file', b'file-id-2')],
2676
 
            basis=[],
2677
 
            target=[('file', b'file-id')],
 
2646
            active=[('other-file', 'file-id'),
 
2647
                    ('file', 'file-id-2')],
 
2648
            basis =[],
 
2649
            target=[('file', 'file-id')],
2678
2650
            )
2679
2651
 
2680
2652
    def test_rename_file_matching_active_state(self):
2681
2653
        state = self.assertUpdate(
2682
 
            active=[('other-file', b'file-id')],
2683
 
            basis=[('file', b'file-id')],
2684
 
            target=[('other-file', b'file-id')],
 
2654
            active=[('other-file', 'file-id')],
 
2655
            basis =[('file', 'file-id')],
 
2656
            target=[('other-file', 'file-id')],
2685
2657
            )
2686
2658
 
2687
2659
    def test_rename_file_missing_in_active_state(self):
2688
2660
        state = self.assertUpdate(
2689
2661
            active=[],
2690
 
            basis=[('file', b'file-id')],
2691
 
            target=[('other-file', b'file-id')],
 
2662
            basis =[('file', 'file-id')],
 
2663
            target=[('other-file', 'file-id')],
2692
2664
            )
2693
2665
 
2694
2666
    def test_rename_file_present_elsewhere_in_active_state(self):
2695
2667
        state = self.assertUpdate(
2696
 
            active=[('third', b'file-id')],
2697
 
            basis=[('file', b'file-id')],
2698
 
            target=[('other-file', b'file-id')],
 
2668
            active=[('third', 'file-id')],
 
2669
            basis =[('file', 'file-id')],
 
2670
            target=[('other-file', 'file-id')],
2699
2671
            )
2700
2672
 
2701
2673
    def test_rename_file_active_state_has_diff_source_file(self):
2702
2674
        state = self.assertUpdate(
2703
 
            active=[('file', b'file-id-2')],
2704
 
            basis=[('file', b'file-id')],
2705
 
            target=[('other-file', b'file-id')],
 
2675
            active=[('file', 'file-id-2')],
 
2676
            basis =[('file', 'file-id')],
 
2677
            target=[('other-file', 'file-id')],
2706
2678
            )
2707
2679
 
2708
2680
    def test_rename_file_active_state_has_diff_target_file(self):
2709
2681
        state = self.assertUpdate(
2710
 
            active=[('other-file', b'file-id-2')],
2711
 
            basis=[('file', b'file-id')],
2712
 
            target=[('other-file', b'file-id')],
 
2682
            active=[('other-file', 'file-id-2')],
 
2683
            basis =[('file', 'file-id')],
 
2684
            target=[('other-file', 'file-id')],
2713
2685
            )
2714
2686
 
2715
2687
    def test_rename_file_active_has_swapped_files(self):
2716
2688
        state = self.assertUpdate(
2717
 
            active=[('file', b'file-id'),
2718
 
                    ('other-file', b'file-id-2')],
2719
 
            basis=[('file', b'file-id'),
2720
 
                   ('other-file', b'file-id-2')],
2721
 
            target=[('file', b'file-id-2'),
2722
 
                    ('other-file', b'file-id')])
 
2689
            active=[('file', 'file-id'),
 
2690
                    ('other-file', 'file-id-2')],
 
2691
            basis= [('file', 'file-id'),
 
2692
                    ('other-file', 'file-id-2')],
 
2693
            target=[('file', 'file-id-2'),
 
2694
                    ('other-file', 'file-id')])
2723
2695
 
2724
2696
    def test_rename_file_basis_has_swapped_files(self):
2725
2697
        state = self.assertUpdate(
2726
 
            active=[('file', b'file-id'),
2727
 
                    ('other-file', b'file-id-2')],
2728
 
            basis=[('file', b'file-id-2'),
2729
 
                   ('other-file', b'file-id')],
2730
 
            target=[('file', b'file-id'),
2731
 
                    ('other-file', b'file-id-2')])
 
2698
            active=[('file', 'file-id'),
 
2699
                    ('other-file', 'file-id-2')],
 
2700
            basis= [('file', 'file-id-2'),
 
2701
                    ('other-file', 'file-id')],
 
2702
            target=[('file', 'file-id'),
 
2703
                    ('other-file', 'file-id-2')])
2732
2704
 
2733
2705
    def test_rename_directory_with_contents(self):
2734
 
        state = self.assertUpdate(  # active matches basis
2735
 
            active=[('dir1/', b'dir-id'),
2736
 
                    ('dir1/file', b'file-id')],
2737
 
            basis=[('dir1/', b'dir-id'),
2738
 
                   ('dir1/file', b'file-id')],
2739
 
            target=[('dir2/', b'dir-id'),
2740
 
                    ('dir2/file', b'file-id')])
2741
 
        state = self.assertUpdate(  # active matches target
2742
 
            active=[('dir2/', b'dir-id'),
2743
 
                    ('dir2/file', b'file-id')],
2744
 
            basis=[('dir1/', b'dir-id'),
2745
 
                   ('dir1/file', b'file-id')],
2746
 
            target=[('dir2/', b'dir-id'),
2747
 
                    ('dir2/file', b'file-id')])
2748
 
        state = self.assertUpdate(  # active empty
 
2706
        state = self.assertUpdate( # active matches basis
 
2707
            active=[('dir1/', 'dir-id'),
 
2708
                    ('dir1/file', 'file-id')],
 
2709
            basis= [('dir1/', 'dir-id'),
 
2710
                    ('dir1/file', 'file-id')],
 
2711
            target=[('dir2/', 'dir-id'),
 
2712
                    ('dir2/file', 'file-id')])
 
2713
        state = self.assertUpdate( # active matches target
 
2714
            active=[('dir2/', 'dir-id'),
 
2715
                    ('dir2/file', 'file-id')],
 
2716
            basis= [('dir1/', 'dir-id'),
 
2717
                    ('dir1/file', 'file-id')],
 
2718
            target=[('dir2/', 'dir-id'),
 
2719
                    ('dir2/file', 'file-id')])
 
2720
        state = self.assertUpdate( # active empty
2749
2721
            active=[],
2750
 
            basis=[('dir1/', b'dir-id'),
2751
 
                   ('dir1/file', b'file-id')],
2752
 
            target=[('dir2/', b'dir-id'),
2753
 
                    ('dir2/file', b'file-id')])
2754
 
        state = self.assertUpdate(  # active present at other location
2755
 
            active=[('dir3/', b'dir-id'),
2756
 
                    ('dir3/file', b'file-id')],
2757
 
            basis=[('dir1/', b'dir-id'),
2758
 
                   ('dir1/file', b'file-id')],
2759
 
            target=[('dir2/', b'dir-id'),
2760
 
                    ('dir2/file', b'file-id')])
2761
 
        state = self.assertUpdate(  # active has different ids
2762
 
            active=[('dir1/', b'dir1-id'),
2763
 
                    ('dir1/file', b'file1-id'),
2764
 
                    ('dir2/', b'dir2-id'),
2765
 
                    ('dir2/file', b'file2-id')],
2766
 
            basis=[('dir1/', b'dir-id'),
2767
 
                   ('dir1/file', b'file-id')],
2768
 
            target=[('dir2/', b'dir-id'),
2769
 
                    ('dir2/file', b'file-id')])
 
2722
            basis= [('dir1/', 'dir-id'),
 
2723
                    ('dir1/file', 'file-id')],
 
2724
            target=[('dir2/', 'dir-id'),
 
2725
                    ('dir2/file', 'file-id')])
 
2726
        state = self.assertUpdate( # active present at other location
 
2727
            active=[('dir3/', 'dir-id'),
 
2728
                    ('dir3/file', 'file-id')],
 
2729
            basis= [('dir1/', 'dir-id'),
 
2730
                    ('dir1/file', 'file-id')],
 
2731
            target=[('dir2/', 'dir-id'),
 
2732
                    ('dir2/file', 'file-id')])
 
2733
        state = self.assertUpdate( # active has different ids
 
2734
            active=[('dir1/', 'dir1-id'),
 
2735
                    ('dir1/file', 'file1-id'),
 
2736
                    ('dir2/', 'dir2-id'),
 
2737
                    ('dir2/file', 'file2-id')],
 
2738
            basis= [('dir1/', 'dir-id'),
 
2739
                    ('dir1/file', 'file-id')],
 
2740
            target=[('dir2/', 'dir-id'),
 
2741
                    ('dir2/file', 'file-id')])
2770
2742
 
2771
2743
    def test_invalid_file_not_present(self):
2772
2744
        state = self.assertBadDelta(
2773
 
            active=[('file', b'file-id')],
2774
 
            basis=[('file', b'file-id')],
2775
 
            delta=[('other-file', 'file', b'file-id')])
 
2745
            active=[('file', 'file-id')],
 
2746
            basis= [('file', 'file-id')],
 
2747
            delta=[('other-file', 'file', 'file-id')])
2776
2748
 
2777
2749
    def test_invalid_new_id_same_path(self):
2778
2750
        # The bad entry comes after
2779
2751
        state = self.assertBadDelta(
2780
 
            active=[('file', b'file-id')],
2781
 
            basis=[('file', b'file-id')],
2782
 
            delta=[(None, 'file', b'file-id-2')])
 
2752
            active=[('file', 'file-id')],
 
2753
            basis= [('file', 'file-id')],
 
2754
            delta=[(None, 'file', 'file-id-2')])
2783
2755
        # The bad entry comes first
2784
2756
        state = self.assertBadDelta(
2785
 
            active=[('file', b'file-id-2')],
2786
 
            basis=[('file', b'file-id-2')],
2787
 
            delta=[(None, 'file', b'file-id')])
 
2757
            active=[('file', 'file-id-2')],
 
2758
            basis=[('file', 'file-id-2')],
 
2759
            delta=[(None, 'file', 'file-id')])
2788
2760
 
2789
2761
    def test_invalid_existing_id(self):
2790
2762
        state = self.assertBadDelta(
2791
 
            active=[('file', b'file-id')],
2792
 
            basis=[('file', b'file-id')],
2793
 
            delta=[(None, 'file', b'file-id')])
 
2763
            active=[('file', 'file-id')],
 
2764
            basis= [('file', 'file-id')],
 
2765
            delta=[(None, 'file', 'file-id')])
2794
2766
 
2795
2767
    def test_invalid_parent_missing(self):
2796
2768
        state = self.assertBadDelta(
2797
2769
            active=[],
2798
 
            basis=[],
2799
 
            delta=[(None, 'path/path2', b'file-id')])
 
2770
            basis= [],
 
2771
            delta=[(None, 'path/path2', 'file-id')])
2800
2772
        # Note: we force the active tree to have the directory, by knowing how
2801
2773
        #       path_to_ie handles entries with missing parents
2802
2774
        state = self.assertBadDelta(
2803
 
            active=[('path/', b'path-id')],
2804
 
            basis=[],
2805
 
            delta=[(None, 'path/path2', b'file-id')])
 
2775
            active=[('path/', 'path-id')],
 
2776
            basis= [],
 
2777
            delta=[(None, 'path/path2', 'file-id')])
2806
2778
        state = self.assertBadDelta(
2807
 
            active=[('path/', b'path-id'),
2808
 
                    ('path/path2', b'file-id')],
2809
 
            basis=[],
2810
 
            delta=[(None, 'path/path2', b'file-id')])
 
2779
            active=[('path/', 'path-id'),
 
2780
                    ('path/path2', 'file-id')],
 
2781
            basis= [],
 
2782
            delta=[(None, 'path/path2', 'file-id')])
2811
2783
 
2812
2784
    def test_renamed_dir_same_path(self):
2813
2785
        # We replace the parent directory, with another parent dir. But the C
2814
2786
        # file doesn't look like it has been moved.
2815
 
        state = self.assertUpdate(  # Same as basis
2816
 
            active=[('dir/', b'A-id'),
2817
 
                    ('dir/B', b'B-id')],
2818
 
            basis=[('dir/', b'A-id'),
2819
 
                   ('dir/B', b'B-id')],
2820
 
            target=[('dir/', b'C-id'),
2821
 
                    ('dir/B', b'B-id')])
2822
 
        state = self.assertUpdate(  # Same as target
2823
 
            active=[('dir/', b'C-id'),
2824
 
                    ('dir/B', b'B-id')],
2825
 
            basis=[('dir/', b'A-id'),
2826
 
                   ('dir/B', b'B-id')],
2827
 
            target=[('dir/', b'C-id'),
2828
 
                    ('dir/B', b'B-id')])
2829
 
        state = self.assertUpdate(  # empty active
 
2787
        state = self.assertUpdate(# Same as basis
 
2788
            active=[('dir/', 'A-id'),
 
2789
                    ('dir/B', 'B-id')],
 
2790
            basis= [('dir/', 'A-id'),
 
2791
                    ('dir/B', 'B-id')],
 
2792
            target=[('dir/', 'C-id'),
 
2793
                    ('dir/B', 'B-id')])
 
2794
        state = self.assertUpdate(# Same as target
 
2795
            active=[('dir/', 'C-id'),
 
2796
                    ('dir/B', 'B-id')],
 
2797
            basis= [('dir/', 'A-id'),
 
2798
                    ('dir/B', 'B-id')],
 
2799
            target=[('dir/', 'C-id'),
 
2800
                    ('dir/B', 'B-id')])
 
2801
        state = self.assertUpdate(# empty active
2830
2802
            active=[],
2831
 
            basis=[('dir/', b'A-id'),
2832
 
                   ('dir/B', b'B-id')],
2833
 
            target=[('dir/', b'C-id'),
2834
 
                    ('dir/B', b'B-id')])
2835
 
        state = self.assertUpdate(  # different active
2836
 
            active=[('dir/', b'D-id'),
2837
 
                    ('dir/B', b'B-id')],
2838
 
            basis=[('dir/', b'A-id'),
2839
 
                   ('dir/B', b'B-id')],
2840
 
            target=[('dir/', b'C-id'),
2841
 
                    ('dir/B', b'B-id')])
 
2803
            basis= [('dir/', 'A-id'),
 
2804
                    ('dir/B', 'B-id')],
 
2805
            target=[('dir/', 'C-id'),
 
2806
                    ('dir/B', 'B-id')])
 
2807
        state = self.assertUpdate(# different active
 
2808
            active=[('dir/', 'D-id'),
 
2809
                    ('dir/B', 'B-id')],
 
2810
            basis= [('dir/', 'A-id'),
 
2811
                    ('dir/B', 'B-id')],
 
2812
            target=[('dir/', 'C-id'),
 
2813
                    ('dir/B', 'B-id')])
2842
2814
 
2843
2815
    def test_parent_child_swap(self):
2844
 
        state = self.assertUpdate(  # Same as basis
2845
 
            active=[('A/', b'A-id'),
2846
 
                    ('A/B/', b'B-id'),
2847
 
                    ('A/B/C', b'C-id')],
2848
 
            basis=[('A/', b'A-id'),
2849
 
                   ('A/B/', b'B-id'),
2850
 
                   ('A/B/C', b'C-id')],
2851
 
            target=[('A/', b'B-id'),
2852
 
                    ('A/B/', b'A-id'),
2853
 
                    ('A/B/C', b'C-id')])
2854
 
        state = self.assertUpdate(  # Same as target
2855
 
            active=[('A/', b'B-id'),
2856
 
                    ('A/B/', b'A-id'),
2857
 
                    ('A/B/C', b'C-id')],
2858
 
            basis=[('A/', b'A-id'),
2859
 
                   ('A/B/', b'B-id'),
2860
 
                   ('A/B/C', b'C-id')],
2861
 
            target=[('A/', b'B-id'),
2862
 
                    ('A/B/', b'A-id'),
2863
 
                    ('A/B/C', b'C-id')])
2864
 
        state = self.assertUpdate(  # empty active
 
2816
        state = self.assertUpdate(# Same as basis
 
2817
            active=[('A/', 'A-id'),
 
2818
                    ('A/B/', 'B-id'),
 
2819
                    ('A/B/C', 'C-id')],
 
2820
            basis= [('A/', 'A-id'),
 
2821
                    ('A/B/', 'B-id'),
 
2822
                    ('A/B/C', 'C-id')],
 
2823
            target=[('A/', 'B-id'),
 
2824
                    ('A/B/', 'A-id'),
 
2825
                    ('A/B/C', 'C-id')])
 
2826
        state = self.assertUpdate(# Same as target
 
2827
            active=[('A/', 'B-id'),
 
2828
                    ('A/B/', 'A-id'),
 
2829
                    ('A/B/C', 'C-id')],
 
2830
            basis= [('A/', 'A-id'),
 
2831
                    ('A/B/', 'B-id'),
 
2832
                    ('A/B/C', 'C-id')],
 
2833
            target=[('A/', 'B-id'),
 
2834
                    ('A/B/', 'A-id'),
 
2835
                    ('A/B/C', 'C-id')])
 
2836
        state = self.assertUpdate(# empty active
2865
2837
            active=[],
2866
 
            basis=[('A/', b'A-id'),
2867
 
                   ('A/B/', b'B-id'),
2868
 
                   ('A/B/C', b'C-id')],
2869
 
            target=[('A/', b'B-id'),
2870
 
                    ('A/B/', b'A-id'),
2871
 
                    ('A/B/C', b'C-id')])
2872
 
        state = self.assertUpdate(  # different active
2873
 
            active=[('D/', b'A-id'),
2874
 
                    ('D/E/', b'B-id'),
2875
 
                    ('F', b'C-id')],
2876
 
            basis=[('A/', b'A-id'),
2877
 
                   ('A/B/', b'B-id'),
2878
 
                   ('A/B/C', b'C-id')],
2879
 
            target=[('A/', b'B-id'),
2880
 
                    ('A/B/', b'A-id'),
2881
 
                    ('A/B/C', b'C-id')])
 
2838
            basis= [('A/', 'A-id'),
 
2839
                    ('A/B/', 'B-id'),
 
2840
                    ('A/B/C', 'C-id')],
 
2841
            target=[('A/', 'B-id'),
 
2842
                    ('A/B/', 'A-id'),
 
2843
                    ('A/B/C', 'C-id')])
 
2844
        state = self.assertUpdate(# different active
 
2845
            active=[('D/', 'A-id'),
 
2846
                    ('D/E/', 'B-id'),
 
2847
                    ('F', 'C-id')],
 
2848
            basis= [('A/', 'A-id'),
 
2849
                    ('A/B/', 'B-id'),
 
2850
                    ('A/B/C', 'C-id')],
 
2851
            target=[('A/', 'B-id'),
 
2852
                    ('A/B/', 'A-id'),
 
2853
                    ('A/B/C', 'C-id')])
2882
2854
 
2883
2855
    def test_change_root_id(self):
2884
 
        state = self.assertUpdate(  # same as basis
2885
 
            active=[('', b'root-id'),
2886
 
                    ('file', b'file-id')],
2887
 
            basis=[('', b'root-id'),
2888
 
                   ('file', b'file-id')],
2889
 
            target=[('', b'target-root-id'),
2890
 
                    ('file', b'file-id')])
2891
 
        state = self.assertUpdate(  # same as target
2892
 
            active=[('', b'target-root-id'),
2893
 
                    ('file', b'file-id')],
2894
 
            basis=[('', b'root-id'),
2895
 
                   ('file', b'file-id')],
2896
 
            target=[('', b'target-root-id'),
2897
 
                    ('file', b'root-id')])
2898
 
        state = self.assertUpdate(  # all different
2899
 
            active=[('', b'active-root-id'),
2900
 
                    ('file', b'file-id')],
2901
 
            basis=[('', b'root-id'),
2902
 
                   ('file', b'file-id')],
2903
 
            target=[('', b'target-root-id'),
2904
 
                    ('file', b'root-id')])
 
2856
        state = self.assertUpdate( # same as basis
 
2857
            active=[('', 'root-id'),
 
2858
                    ('file', 'file-id')],
 
2859
            basis= [('', 'root-id'),
 
2860
                    ('file', 'file-id')],
 
2861
            target=[('', 'target-root-id'),
 
2862
                    ('file', 'file-id')])
 
2863
        state = self.assertUpdate( # same as target
 
2864
            active=[('', 'target-root-id'),
 
2865
                    ('file', 'file-id')],
 
2866
            basis= [('', 'root-id'),
 
2867
                    ('file', 'file-id')],
 
2868
            target=[('', 'target-root-id'),
 
2869
                    ('file', 'root-id')])
 
2870
        state = self.assertUpdate( # all different
 
2871
            active=[('', 'active-root-id'),
 
2872
                    ('file', 'file-id')],
 
2873
            basis= [('', 'root-id'),
 
2874
                    ('file', 'file-id')],
 
2875
            target=[('', 'target-root-id'),
 
2876
                    ('file', 'root-id')])
2905
2877
 
2906
2878
    def test_change_file_absent_in_active(self):
2907
2879
        state = self.assertUpdate(
2908
2880
            active=[],
2909
 
            basis=[('file', b'file-id')],
2910
 
            target=[('file', b'file-id')])
 
2881
            basis= [('file', 'file-id')],
 
2882
            target=[('file', 'file-id')])
2911
2883
 
2912
2884
    def test_invalid_changed_file(self):
2913
 
        state = self.assertBadDelta(  # Not present in basis
2914
 
            active=[('file', b'file-id')],
2915
 
            basis=[],
2916
 
            delta=[('file', 'file', b'file-id')])
2917
 
        state = self.assertBadDelta(  # present at another location in basis
2918
 
            active=[('file', b'file-id')],
2919
 
            basis=[('other-file', b'file-id')],
2920
 
            delta=[('file', 'file', b'file-id')])
 
2885
        state = self.assertBadDelta( # Not present in basis
 
2886
            active=[('file', 'file-id')],
 
2887
            basis= [],
 
2888
            delta=[('file', 'file', 'file-id')])
 
2889
        state = self.assertBadDelta( # present at another location in basis
 
2890
            active=[('file', 'file-id')],
 
2891
            basis= [('other-file', 'file-id')],
 
2892
            delta=[('file', 'file', 'file-id')])