/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 breezy/tests/test_dirstate.py

  • Committer: Jelmer Vernooij
  • Date: 2017-07-23 22:06:41 UTC
  • mfrom: (6738 trunk)
  • mto: This revision was merged to the branch mainline in revision 6739.
  • Revision ID: jelmer@jelmer.uk-20170723220641-69eczax9bmv8d6kk
Merge trunk, address review comments.

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