/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_helpers.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
# FIXME: we should also parametrize against SHA1Provider !
52
52
 
53
53
ue_scenarios = [('dirstate_Python',
54
 
    {'update_entry': dirstate.py_update_entry})]
 
54
                 {'update_entry': dirstate.py_update_entry})]
55
55
if compiled_dirstate_helpers_feature.available():
56
56
    update_entry = compiled_dirstate_helpers_feature.module.update_entry
57
57
    ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
58
58
 
59
59
pe_scenarios = [('dirstate_Python',
60
 
    {'_process_entry': dirstate.ProcessEntryPython})]
 
60
                 {'_process_entry': dirstate.ProcessEntryPython})]
61
61
if compiled_dirstate_helpers_feature.available():
62
62
    process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
63
63
    pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
65
65
helper_scenarios = [('dirstate_Python', {'helpers': _dirstate_helpers_py})]
66
66
if compiled_dirstate_helpers_feature.available():
67
67
    helper_scenarios.append(('dirstate_Pyrex',
68
 
        {'helpers': compiled_dirstate_helpers_feature.module}))
 
68
                             {'helpers': compiled_dirstate_helpers_feature.module}))
69
69
 
70
70
 
71
71
class TestBisectPathMixin(object):
120
120
                            bisect_split_idx, bisect_path_idx, path)
121
121
                         )
122
122
        if exists:
123
 
            self.assertEqual(path, paths[bisect_path_idx+offset])
 
123
            self.assertEqual(path, paths[bisect_path_idx + offset])
124
124
 
125
125
    def split_for_dirblocks(self, paths):
126
126
        dir_split_paths = []
127
127
        for path in paths:
128
128
            dirname, basename = os.path.split(path)
129
 
            dir_split_paths.append((dirname.split('/'), basename))
 
129
            dir_split_paths.append((dirname.split(b'/'), basename))
130
130
        dir_split_paths.sort()
131
131
        return dir_split_paths
132
132
 
133
133
    def test_simple(self):
134
134
        """In the simple case it works just like bisect_left"""
135
 
        paths = ['', 'a', 'b', 'c', 'd']
 
135
        paths = [b'', b'a', b'b', b'c', b'd']
136
136
        split_paths = self.split_for_dirblocks(paths)
137
137
        for path in paths:
138
138
            self.assertBisect(paths, split_paths, path, exists=True)
139
 
        self.assertBisect(paths, split_paths, '_', exists=False)
140
 
        self.assertBisect(paths, split_paths, 'aa', exists=False)
141
 
        self.assertBisect(paths, split_paths, 'bb', exists=False)
142
 
        self.assertBisect(paths, split_paths, 'cc', exists=False)
143
 
        self.assertBisect(paths, split_paths, 'dd', exists=False)
144
 
        self.assertBisect(paths, split_paths, 'a/a', exists=False)
145
 
        self.assertBisect(paths, split_paths, 'b/b', exists=False)
146
 
        self.assertBisect(paths, split_paths, 'c/c', exists=False)
147
 
        self.assertBisect(paths, split_paths, 'd/d', exists=False)
 
139
        self.assertBisect(paths, split_paths, b'_', exists=False)
 
140
        self.assertBisect(paths, split_paths, b'aa', exists=False)
 
141
        self.assertBisect(paths, split_paths, b'bb', exists=False)
 
142
        self.assertBisect(paths, split_paths, b'cc', exists=False)
 
143
        self.assertBisect(paths, split_paths, b'dd', exists=False)
 
144
        self.assertBisect(paths, split_paths, b'a/a', exists=False)
 
145
        self.assertBisect(paths, split_paths, b'b/b', exists=False)
 
146
        self.assertBisect(paths, split_paths, b'c/c', exists=False)
 
147
        self.assertBisect(paths, split_paths, b'd/d', exists=False)
148
148
 
149
149
    def test_involved(self):
150
150
        """This is where bisect_path_* diverges slightly."""
181
181
        # children are mentioned.
182
182
        # So all the root-directory paths, then all the
183
183
        # first sub directory, etc.
184
 
        paths = [# content of '/'
185
 
                 '', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
 
184
        paths = [  # content of '/'
 
185
            b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
186
186
                 # content of 'a/'
187
 
                 'a/a', 'a/a-a', 'a/a-z',
188
 
                 'a/a=a', 'a/a=z',
189
 
                 'a/z', 'a/z-a', 'a/z-z',
190
 
                 'a/z=a', 'a/z=z',
 
187
                 b'a/a', b'a/a-a', b'a/a-z',
 
188
                 b'a/a=a', b'a/a=z',
 
189
                 b'a/z', b'a/z-a', b'a/z-z',
 
190
                 b'a/z=a', b'a/z=z',
191
191
                 # content of 'a/a/'
192
 
                 'a/a/a', 'a/a/z',
 
192
                 b'a/a/a', b'a/a/z',
193
193
                 # content of 'a/a-a'
194
 
                 'a/a-a/a',
 
194
                 b'a/a-a/a',
195
195
                 # content of 'a/a-z'
196
 
                 'a/a-z/z',
 
196
                 b'a/a-z/z',
197
197
                 # content of 'a/a=a'
198
 
                 'a/a=a/a',
 
198
                 b'a/a=a/a',
199
199
                 # content of 'a/a=z'
200
 
                 'a/a=z/z',
 
200
                 b'a/a=z/z',
201
201
                 # content of 'a/z/'
202
 
                 'a/z/a', 'a/z/z',
 
202
                 b'a/z/a', b'a/z/z',
203
203
                 # content of 'a-a'
204
 
                 'a-a/a',
 
204
                 b'a-a/a',
205
205
                 # content of 'a-z'
206
 
                 'a-z/z',
 
206
                 b'a-z/z',
207
207
                 # content of 'a=a'
208
 
                 'a=a/a',
 
208
                 b'a=a/a',
209
209
                 # content of 'a=z'
210
 
                 'a=z/z',
211
 
                ]
 
210
                 b'a=z/z',
 
211
            ]
212
212
        split_paths = self.split_for_dirblocks(paths)
213
213
        sorted_paths = []
214
214
        for dir_parts, basename in split_paths:
215
 
            if dir_parts == ['']:
 
215
            if dir_parts == [b'']:
216
216
                sorted_paths.append(basename)
217
217
            else:
218
 
                sorted_paths.append('/'.join(dir_parts + [basename]))
 
218
                sorted_paths.append(b'/'.join(dir_parts + [basename]))
219
219
 
220
220
        self.assertEqual(sorted_paths, paths)
221
221
 
294
294
        bisect_dirblock = self.get_bisect_dirblock()
295
295
        self.assertIsInstance(dirblocks, list)
296
296
        bisect_split_idx = bisect_dirblock(dirblocks, path, *args, **kwargs)
297
 
        split_dirblock = (path.split('/'), [])
 
297
        split_dirblock = (path.split(b'/'), [])
298
298
        bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
299
299
                                             *args)
300
300
        self.assertEqual(bisect_left_idx, bisect_split_idx,
309
309
        Also, ensure that the paths are in proper sorted order.
310
310
        """
311
311
        dirblocks = [(path, []) for path in paths]
312
 
        split_dirblocks = [(path.split('/'), []) for path in paths]
 
312
        split_dirblocks = [(path.split(b'/'), []) for path in paths]
313
313
        self.assertEqual(sorted(split_dirblocks), split_dirblocks)
314
314
        return dirblocks, split_dirblocks
315
315
 
316
316
    def test_simple(self):
317
317
        """In the simple case it works just like bisect_left"""
318
 
        paths = ['', 'a', 'b', 'c', 'd']
 
318
        paths = [b'', b'a', b'b', b'c', b'd']
319
319
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
320
320
        for path in paths:
321
321
            self.assertBisect(dirblocks, split_dirblocks, path)
322
 
        self.assertBisect(dirblocks, split_dirblocks, '_')
323
 
        self.assertBisect(dirblocks, split_dirblocks, 'aa')
324
 
        self.assertBisect(dirblocks, split_dirblocks, 'bb')
325
 
        self.assertBisect(dirblocks, split_dirblocks, 'cc')
326
 
        self.assertBisect(dirblocks, split_dirblocks, 'dd')
327
 
        self.assertBisect(dirblocks, split_dirblocks, 'a/a')
328
 
        self.assertBisect(dirblocks, split_dirblocks, 'b/b')
329
 
        self.assertBisect(dirblocks, split_dirblocks, 'c/c')
330
 
        self.assertBisect(dirblocks, split_dirblocks, 'd/d')
 
322
        self.assertBisect(dirblocks, split_dirblocks, b'_')
 
323
        self.assertBisect(dirblocks, split_dirblocks, b'aa')
 
324
        self.assertBisect(dirblocks, split_dirblocks, b'bb')
 
325
        self.assertBisect(dirblocks, split_dirblocks, b'cc')
 
326
        self.assertBisect(dirblocks, split_dirblocks, b'dd')
 
327
        self.assertBisect(dirblocks, split_dirblocks, b'a/a')
 
328
        self.assertBisect(dirblocks, split_dirblocks, b'b/b')
 
329
        self.assertBisect(dirblocks, split_dirblocks, b'c/c')
 
330
        self.assertBisect(dirblocks, split_dirblocks, b'd/d')
331
331
 
332
332
    def test_involved(self):
333
333
        """This is where bisect_left diverges slightly."""
334
 
        paths = ['', 'a',
335
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
336
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
337
 
                 'a-a', 'a-z',
338
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
339
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
340
 
                 'z-a', 'z-z',
341
 
                ]
 
334
        paths = [b'', b'a',
 
335
                 b'a/a', b'a/a/a', b'a/a/z', b'a/a-a', b'a/a-z',
 
336
                 b'a/z', b'a/z/a', b'a/z/z', b'a/z-a', b'a/z-z',
 
337
                 b'a-a', b'a-z',
 
338
                 b'z', b'z/a/a', b'z/a/z', b'z/a-a', b'z/a-z',
 
339
                 b'z/z', b'z/z/a', b'z/z/z', b'z/z-a', b'z/z-z',
 
340
                 b'z-a', b'z-z',
 
341
                 ]
342
342
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
343
343
        for path in paths:
344
344
            self.assertBisect(dirblocks, split_dirblocks, path)
345
345
 
346
346
    def test_involved_cached(self):
347
347
        """This is where bisect_left diverges slightly."""
348
 
        paths = ['', 'a',
349
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
350
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
351
 
                 'a-a', 'a-z',
352
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
353
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
354
 
                 'z-a', 'z-z',
355
 
                ]
 
348
        paths = [b'', b'a',
 
349
                 b'a/a', b'a/a/a', b'a/a/z', b'a/a-a', b'a/a-z',
 
350
                 b'a/z', b'a/z/a', b'a/z/z', b'a/z-a', b'a/z-z',
 
351
                 b'a-a', b'a-z',
 
352
                 b'z', b'z/a/a', b'z/a/z', b'z/a-a', b'z/a-z',
 
353
                 b'z/z', b'z/z/a', b'z/z/z', b'z/z-a', b'z/z-z',
 
354
                 b'z-a', b'z-z',
 
355
                 ]
356
356
        cache = {}
357
357
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
358
358
        for path in paths:
414
414
 
415
415
    def test_cmp_empty(self):
416
416
        """Compare against the empty string."""
417
 
        self.assertCmpByDirs(0, '', '')
418
 
        self.assertCmpByDirs(1, 'a', '')
419
 
        self.assertCmpByDirs(1, 'ab', '')
420
 
        self.assertCmpByDirs(1, 'abc', '')
421
 
        self.assertCmpByDirs(1, 'abcd', '')
422
 
        self.assertCmpByDirs(1, 'abcde', '')
423
 
        self.assertCmpByDirs(1, 'abcdef', '')
424
 
        self.assertCmpByDirs(1, 'abcdefg', '')
425
 
        self.assertCmpByDirs(1, 'abcdefgh', '')
426
 
        self.assertCmpByDirs(1, 'abcdefghi', '')
427
 
        self.assertCmpByDirs(1, 'test/ing/a/path/', '')
 
417
        self.assertCmpByDirs(0, b'', b'')
 
418
        self.assertCmpByDirs(1, b'a', b'')
 
419
        self.assertCmpByDirs(1, b'ab', b'')
 
420
        self.assertCmpByDirs(1, b'abc', b'')
 
421
        self.assertCmpByDirs(1, b'abcd', b'')
 
422
        self.assertCmpByDirs(1, b'abcde', b'')
 
423
        self.assertCmpByDirs(1, b'abcdef', b'')
 
424
        self.assertCmpByDirs(1, b'abcdefg', b'')
 
425
        self.assertCmpByDirs(1, b'abcdefgh', b'')
 
426
        self.assertCmpByDirs(1, b'abcdefghi', b'')
 
427
        self.assertCmpByDirs(1, b'test/ing/a/path/', b'')
428
428
 
429
429
    def test_cmp_same_str(self):
430
430
        """Compare the same string"""
431
 
        self.assertCmpByDirs(0, 'a', 'a')
432
 
        self.assertCmpByDirs(0, 'ab', 'ab')
433
 
        self.assertCmpByDirs(0, 'abc', 'abc')
434
 
        self.assertCmpByDirs(0, 'abcd', 'abcd')
435
 
        self.assertCmpByDirs(0, 'abcde', 'abcde')
436
 
        self.assertCmpByDirs(0, 'abcdef', 'abcdef')
437
 
        self.assertCmpByDirs(0, 'abcdefg', 'abcdefg')
438
 
        self.assertCmpByDirs(0, 'abcdefgh', 'abcdefgh')
439
 
        self.assertCmpByDirs(0, 'abcdefghi', 'abcdefghi')
440
 
        self.assertCmpByDirs(0, 'testing a long string', 'testing a long string')
441
 
        self.assertCmpByDirs(0, 'x'*10000, 'x'*10000)
442
 
        self.assertCmpByDirs(0, 'a/b', 'a/b')
443
 
        self.assertCmpByDirs(0, 'a/b/c', 'a/b/c')
444
 
        self.assertCmpByDirs(0, 'a/b/c/d', 'a/b/c/d')
445
 
        self.assertCmpByDirs(0, 'a/b/c/d/e', 'a/b/c/d/e')
 
431
        self.assertCmpByDirs(0, b'a', b'a')
 
432
        self.assertCmpByDirs(0, b'ab', b'ab')
 
433
        self.assertCmpByDirs(0, b'abc', b'abc')
 
434
        self.assertCmpByDirs(0, b'abcd', b'abcd')
 
435
        self.assertCmpByDirs(0, b'abcde', b'abcde')
 
436
        self.assertCmpByDirs(0, b'abcdef', b'abcdef')
 
437
        self.assertCmpByDirs(0, b'abcdefg', b'abcdefg')
 
438
        self.assertCmpByDirs(0, b'abcdefgh', b'abcdefgh')
 
439
        self.assertCmpByDirs(0, b'abcdefghi', b'abcdefghi')
 
440
        self.assertCmpByDirs(0, b'testing a long string',
 
441
                             b'testing a long string')
 
442
        self.assertCmpByDirs(0, b'x' * 10000, b'x' * 10000)
 
443
        self.assertCmpByDirs(0, b'a/b', b'a/b')
 
444
        self.assertCmpByDirs(0, b'a/b/c', b'a/b/c')
 
445
        self.assertCmpByDirs(0, b'a/b/c/d', b'a/b/c/d')
 
446
        self.assertCmpByDirs(0, b'a/b/c/d/e', b'a/b/c/d/e')
446
447
 
447
448
    def test_simple_paths(self):
448
449
        """Compare strings that act like normal string comparison"""
449
 
        self.assertCmpByDirs(-1, 'a', 'b')
450
 
        self.assertCmpByDirs(-1, 'aa', 'ab')
451
 
        self.assertCmpByDirs(-1, 'ab', 'bb')
452
 
        self.assertCmpByDirs(-1, 'aaa', 'aab')
453
 
        self.assertCmpByDirs(-1, 'aab', 'abb')
454
 
        self.assertCmpByDirs(-1, 'abb', 'bbb')
455
 
        self.assertCmpByDirs(-1, 'aaaa', 'aaab')
456
 
        self.assertCmpByDirs(-1, 'aaab', 'aabb')
457
 
        self.assertCmpByDirs(-1, 'aabb', 'abbb')
458
 
        self.assertCmpByDirs(-1, 'abbb', 'bbbb')
459
 
        self.assertCmpByDirs(-1, 'aaaaa', 'aaaab')
460
 
        self.assertCmpByDirs(-1, 'a/a', 'a/b')
461
 
        self.assertCmpByDirs(-1, 'a/b', 'b/b')
462
 
        self.assertCmpByDirs(-1, 'a/a/a', 'a/a/b')
463
 
        self.assertCmpByDirs(-1, 'a/a/b', 'a/b/b')
464
 
        self.assertCmpByDirs(-1, 'a/b/b', 'b/b/b')
465
 
        self.assertCmpByDirs(-1, 'a/a/a/a', 'a/a/a/b')
466
 
        self.assertCmpByDirs(-1, 'a/a/a/b', 'a/a/b/b')
467
 
        self.assertCmpByDirs(-1, 'a/a/b/b', 'a/b/b/b')
468
 
        self.assertCmpByDirs(-1, 'a/b/b/b', 'b/b/b/b')
469
 
        self.assertCmpByDirs(-1, 'a/a/a/a/a', 'a/a/a/a/b')
 
450
        self.assertCmpByDirs(-1, b'a', b'b')
 
451
        self.assertCmpByDirs(-1, b'aa', b'ab')
 
452
        self.assertCmpByDirs(-1, b'ab', b'bb')
 
453
        self.assertCmpByDirs(-1, b'aaa', b'aab')
 
454
        self.assertCmpByDirs(-1, b'aab', b'abb')
 
455
        self.assertCmpByDirs(-1, b'abb', b'bbb')
 
456
        self.assertCmpByDirs(-1, b'aaaa', b'aaab')
 
457
        self.assertCmpByDirs(-1, b'aaab', b'aabb')
 
458
        self.assertCmpByDirs(-1, b'aabb', b'abbb')
 
459
        self.assertCmpByDirs(-1, b'abbb', b'bbbb')
 
460
        self.assertCmpByDirs(-1, b'aaaaa', b'aaaab')
 
461
        self.assertCmpByDirs(-1, b'a/a', b'a/b')
 
462
        self.assertCmpByDirs(-1, b'a/b', b'b/b')
 
463
        self.assertCmpByDirs(-1, b'a/a/a', b'a/a/b')
 
464
        self.assertCmpByDirs(-1, b'a/a/b', b'a/b/b')
 
465
        self.assertCmpByDirs(-1, b'a/b/b', b'b/b/b')
 
466
        self.assertCmpByDirs(-1, b'a/a/a/a', b'a/a/a/b')
 
467
        self.assertCmpByDirs(-1, b'a/a/a/b', b'a/a/b/b')
 
468
        self.assertCmpByDirs(-1, b'a/a/b/b', b'a/b/b/b')
 
469
        self.assertCmpByDirs(-1, b'a/b/b/b', b'b/b/b/b')
 
470
        self.assertCmpByDirs(-1, b'a/a/a/a/a', b'a/a/a/a/b')
470
471
 
471
472
    def test_tricky_paths(self):
472
 
        self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/cc/ef')
473
 
        self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/c/ef')
474
 
        self.assertCmpByDirs(-1, 'ab/cd/ef', 'ab/cd-ef')
475
 
        self.assertCmpByDirs(-1, 'ab/cd', 'ab/cd-')
476
 
        self.assertCmpByDirs(-1, 'ab/cd', 'ab-cd')
 
473
        self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/cc/ef')
 
474
        self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/c/ef')
 
475
        self.assertCmpByDirs(-1, b'ab/cd/ef', b'ab/cd-ef')
 
476
        self.assertCmpByDirs(-1, b'ab/cd', b'ab/cd-')
 
477
        self.assertCmpByDirs(-1, b'ab/cd', b'ab-cd')
477
478
 
478
479
    def test_cmp_unicode_not_allowed(self):
479
480
        lt_by_dirs = self.get_lt_by_dirs()
480
 
        self.assertRaises(TypeError, lt_by_dirs, u'Unicode', 'str')
481
 
        self.assertRaises(TypeError, lt_by_dirs, 'str', u'Unicode')
 
481
        self.assertRaises(TypeError, lt_by_dirs, u'Unicode', b'str')
 
482
        self.assertRaises(TypeError, lt_by_dirs, b'str', u'Unicode')
482
483
        self.assertRaises(TypeError, lt_by_dirs, u'Unicode', u'Unicode')
483
484
 
484
485
    def test_cmp_non_ascii(self):
485
 
        self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
486
 
        self.assertCmpByDirs(-1, 'a', '\xc3\xa5') # u'a', u'\xe5'
487
 
        self.assertCmpByDirs(-1, 'b', '\xc2\xb5') # u'b', u'\xb5'
488
 
        self.assertCmpByDirs(-1, 'a/b', 'a/\xc3\xa5') # u'a/b', u'a/\xe5'
489
 
        self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
 
486
        self.assertCmpByDirs(-1, b'\xc2\xb5', b'\xc3\xa5')  # u'\xb5', u'\xe5'
 
487
        self.assertCmpByDirs(-1, b'a', b'\xc3\xa5')  # u'a', u'\xe5'
 
488
        self.assertCmpByDirs(-1, b'b', b'\xc2\xb5')  # u'b', u'\xb5'
 
489
        self.assertCmpByDirs(-1, b'a/b', b'a/\xc3\xa5')  # u'a/b', u'a/\xe5'
 
490
        self.assertCmpByDirs(-1, b'b/a', b'b/\xc2\xb5')  # u'b/a', u'b/\xb5'
490
491
 
491
492
 
492
493
class TestCompiledLtByDirs(TestLtByDirs):
525
526
        # First, make sure the paths being passed in are correct
526
527
        def _key(p):
527
528
            dirname, basename = os.path.split(p)
528
 
            return dirname.split('/'), basename
 
529
            return dirname.split(b'/'), basename
529
530
        self.assertEqual(sorted(paths, key=_key), paths)
530
531
 
531
532
        lt_path_by_dirblock = self.get_lt_path_by_dirblock()
533
534
            for idx2, path2 in enumerate(paths):
534
535
                lt_result = lt_path_by_dirblock(path1, path2)
535
536
                self.assertEqual(idx1 < idx2, lt_result,
536
 
                        '%s did not state that %r < %r, lt=%s'
537
 
                        % (lt_path_by_dirblock.__name__,
538
 
                           path1, path2, lt_result))
 
537
                                 '%s did not state that %r < %r, lt=%s'
 
538
                                 % (lt_path_by_dirblock.__name__,
 
539
                                    path1, path2, lt_result))
539
540
 
540
541
    def test_cmp_simple_paths(self):
541
542
        """Compare against the empty string."""
542
 
        self.assertLtPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
543
 
        self.assertLtPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
 
543
        self.assertLtPathByDirblock(
 
544
            [b'', b'a', b'ab', b'abc', b'a/b/c', b'b/d/e'])
 
545
        self.assertLtPathByDirblock([b'kl', b'ab/cd', b'ab/ef', b'gh/ij'])
544
546
 
545
547
    def test_tricky_paths(self):
546
548
        self.assertLtPathByDirblock([
547
549
            # Contents of ''
548
 
            '', 'a', 'a-a', 'a=a', 'b',
 
550
            b'', b'a', b'a-a', b'a=a', b'b',
549
551
            # Contents of 'a'
550
 
            'a/a', 'a/a-a', 'a/a=a', 'a/b',
 
552
            b'a/a', b'a/a-a', b'a/a=a', b'a/b',
551
553
            # Contents of 'a/a'
552
 
            'a/a/a', 'a/a/a-a', 'a/a/a=a',
 
554
            b'a/a/a', b'a/a/a-a', b'a/a/a=a',
553
555
            # Contents of 'a/a/a'
554
 
            'a/a/a/a', 'a/a/a/b',
 
556
            b'a/a/a/a', b'a/a/a/b',
555
557
            # Contents of 'a/a/a-a',
556
 
            'a/a/a-a/a', 'a/a/a-a/b',
 
558
            b'a/a/a-a/a', b'a/a/a-a/b',
557
559
            # Contents of 'a/a/a=a',
558
 
            'a/a/a=a/a', 'a/a/a=a/b',
 
560
            b'a/a/a=a/a', b'a/a/a=a/b',
559
561
            # Contents of 'a/a-a'
560
 
            'a/a-a/a',
 
562
            b'a/a-a/a',
561
563
            # Contents of 'a/a-a/a'
562
 
            'a/a-a/a/a', 'a/a-a/a/b',
 
564
            b'a/a-a/a/a', b'a/a-a/a/b',
563
565
            # Contents of 'a/a=a'
564
 
            'a/a=a/a',
 
566
            b'a/a=a/a',
565
567
            # Contents of 'a/b'
566
 
            'a/b/a', 'a/b/b',
 
568
            b'a/b/a', b'a/b/b',
567
569
            # Contents of 'a-a',
568
 
            'a-a/a', 'a-a/b',
 
570
            b'a-a/a', b'a-a/b',
569
571
            # Contents of 'a=a',
570
 
            'a=a/a', 'a=a/b',
 
572
            b'a=a/a', b'a=a/b',
571
573
            # Contents of 'b',
572
 
            'b/a', 'b/b',
 
574
            b'b/a', b'b/b',
573
575
            ])
574
576
        self.assertLtPathByDirblock([
575
 
                 # content of '/'
576
 
                 '', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
 
577
            # content of '/'
 
578
            b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
577
579
                 # content of 'a/'
578
 
                 'a/a', 'a/a-a', 'a/a-z',
579
 
                 'a/a=a', 'a/a=z',
580
 
                 'a/z', 'a/z-a', 'a/z-z',
581
 
                 'a/z=a', 'a/z=z',
 
580
                 b'a/a', b'a/a-a', b'a/a-z',
 
581
                 b'a/a=a', b'a/a=z',
 
582
                 b'a/z', b'a/z-a', b'a/z-z',
 
583
                 b'a/z=a', b'a/z=z',
582
584
                 # content of 'a/a/'
583
 
                 'a/a/a', 'a/a/z',
 
585
                 b'a/a/a', b'a/a/z',
584
586
                 # content of 'a/a-a'
585
 
                 'a/a-a/a',
 
587
                 b'a/a-a/a',
586
588
                 # content of 'a/a-z'
587
 
                 'a/a-z/z',
 
589
                 b'a/a-z/z',
588
590
                 # content of 'a/a=a'
589
 
                 'a/a=a/a',
 
591
                 b'a/a=a/a',
590
592
                 # content of 'a/a=z'
591
 
                 'a/a=z/z',
 
593
                 b'a/a=z/z',
592
594
                 # content of 'a/z/'
593
 
                 'a/z/a', 'a/z/z',
 
595
                 b'a/z/a', b'a/z/z',
594
596
                 # content of 'a-a'
595
 
                 'a-a/a',
 
597
                 b'a-a/a',
596
598
                 # content of 'a-z'
597
 
                 'a-z/z',
 
599
                 b'a-z/z',
598
600
                 # content of 'a=a'
599
 
                 'a=a/a',
 
601
                 b'a=a/a',
600
602
                 # content of 'a=z'
601
 
                 'a=z/z',
602
 
                ])
 
603
                 b'a=z/z',
 
604
            ])
603
605
 
604
606
    def test_unicode_not_allowed(self):
605
607
        lt_path_by_dirblock = self.get_lt_path_by_dirblock()
613
615
    def test_nonascii(self):
614
616
        self.assertLtPathByDirblock([
615
617
            # content of '/'
616
 
            '', 'a', '\xc2\xb5', '\xc3\xa5',
 
618
            b'', b'a', b'\xc2\xb5', b'\xc3\xa5',
617
619
            # content of 'a'
618
 
            'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
 
620
            b'a/a', b'a/\xc2\xb5', b'a/\xc3\xa5',
619
621
            # content of 'a/a'
620
 
            'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
 
622
            b'a/a/a', b'a/a/\xc2\xb5', b'a/a/\xc3\xa5',
621
623
            # content of 'a/\xc2\xb5'
622
 
            'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
 
624
            b'a/\xc2\xb5/a', b'a/\xc2\xb5/\xc2\xb5', b'a/\xc2\xb5/\xc3\xa5',
623
625
            # content of 'a/\xc3\xa5'
624
 
            'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
 
626
            b'a/\xc3\xa5/a', b'a/\xc3\xa5/\xc2\xb5', b'a/\xc3\xa5/\xc3\xa5',
625
627
            # content of '\xc2\xb5'
626
 
            '\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
 
628
            b'\xc2\xb5/a', b'\xc2\xb5/\xc2\xb5', b'\xc2\xb5/\xc3\xa5',
627
629
            # content of '\xc2\xe5'
628
 
            '\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
 
630
            b'\xc3\xa5/a', b'\xc3\xa5/\xc2\xb5', b'\xc3\xa5/\xc3\xa5',
629
631
            ])
630
632
 
631
633
 
649
651
        self.assertEqual(expected, _py_memrchr(s, c))
650
652
 
651
653
    def test_missing(self):
652
 
        self.assertMemRChr(None, '', 'a')
653
 
        self.assertMemRChr(None, '', 'c')
654
 
        self.assertMemRChr(None, 'abcdefghijklm', 'q')
655
 
        self.assertMemRChr(None, 'aaaaaaaaaaaaaaaaaaaaaaa', 'b')
 
654
        self.assertMemRChr(None, b'', b'a')
 
655
        self.assertMemRChr(None, b'', b'c')
 
656
        self.assertMemRChr(None, b'abcdefghijklm', b'q')
 
657
        self.assertMemRChr(None, b'aaaaaaaaaaaaaaaaaaaaaaa', b'b')
656
658
 
657
659
    def test_single_entry(self):
658
 
        self.assertMemRChr(0, 'abcdefghijklm', 'a')
659
 
        self.assertMemRChr(1, 'abcdefghijklm', 'b')
660
 
        self.assertMemRChr(2, 'abcdefghijklm', 'c')
661
 
        self.assertMemRChr(10, 'abcdefghijklm', 'k')
662
 
        self.assertMemRChr(11, 'abcdefghijklm', 'l')
663
 
        self.assertMemRChr(12, 'abcdefghijklm', 'm')
 
660
        self.assertMemRChr(0, b'abcdefghijklm', b'a')
 
661
        self.assertMemRChr(1, b'abcdefghijklm', b'b')
 
662
        self.assertMemRChr(2, b'abcdefghijklm', b'c')
 
663
        self.assertMemRChr(10, b'abcdefghijklm', b'k')
 
664
        self.assertMemRChr(11, b'abcdefghijklm', b'l')
 
665
        self.assertMemRChr(12, b'abcdefghijklm', b'm')
664
666
 
665
667
    def test_multiple(self):
666
 
        self.assertMemRChr(10, 'abcdefjklmabcdefghijklm', 'a')
667
 
        self.assertMemRChr(11, 'abcdefjklmabcdefghijklm', 'b')
668
 
        self.assertMemRChr(12, 'abcdefjklmabcdefghijklm', 'c')
669
 
        self.assertMemRChr(20, 'abcdefjklmabcdefghijklm', 'k')
670
 
        self.assertMemRChr(21, 'abcdefjklmabcdefghijklm', 'l')
671
 
        self.assertMemRChr(22, 'abcdefjklmabcdefghijklm', 'm')
672
 
        self.assertMemRChr(22, 'aaaaaaaaaaaaaaaaaaaaaaa', 'a')
 
668
        self.assertMemRChr(10, b'abcdefjklmabcdefghijklm', b'a')
 
669
        self.assertMemRChr(11, b'abcdefjklmabcdefghijklm', b'b')
 
670
        self.assertMemRChr(12, b'abcdefjklmabcdefghijklm', b'c')
 
671
        self.assertMemRChr(20, b'abcdefjklmabcdefghijklm', b'k')
 
672
        self.assertMemRChr(21, b'abcdefjklmabcdefghijklm', b'l')
 
673
        self.assertMemRChr(22, b'abcdefjklmabcdefghijklm', b'm')
 
674
        self.assertMemRChr(22, b'aaaaaaaaaaaaaaaaaaaaaaa', b'a')
673
675
 
674
676
    def test_with_nulls(self):
675
 
        self.assertMemRChr(10, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'a')
676
 
        self.assertMemRChr(11, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'b')
677
 
        self.assertMemRChr(12, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'c')
678
 
        self.assertMemRChr(20, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'k')
679
 
        self.assertMemRChr(21, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'l')
680
 
        self.assertMemRChr(22, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'm')
681
 
        self.assertMemRChr(22, 'aaa\0\0\0aaaaaaa\0\0\0aaaaaaa', 'a')
682
 
        self.assertMemRChr(9, '\0\0\0\0\0\0\0\0\0\0', '\0')
 
677
        self.assertMemRChr(10, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'a')
 
678
        self.assertMemRChr(11, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'b')
 
679
        self.assertMemRChr(12, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'c')
 
680
        self.assertMemRChr(20, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'k')
 
681
        self.assertMemRChr(21, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'l')
 
682
        self.assertMemRChr(22, b'abc\0\0\0jklmabc\0\0\0ghijklm', b'm')
 
683
        self.assertMemRChr(22, b'aaa\0\0\0aaaaaaa\0\0\0aaaaaaa', b'a')
 
684
        self.assertMemRChr(9, b'\0\0\0\0\0\0\0\0\0\0', b'\0')
683
685
 
684
686
 
685
687
class TestReadDirblocks(test_dirstate.TestCaseWithDirState):
719
721
        f = open('dirstate', 'ab')
720
722
        try:
721
723
            # Add bogus trailing garbage
722
 
            f.write('bogus\n')
 
724
            f.write(b'bogus\n')
723
725
        finally:
724
726
            f.close()
725
727
            state.lock_read()
815
817
        """Create a DirState tracking a single object named 'a'"""
816
818
        state = test_dirstate.InstrumentedDirState.initialize('dirstate')
817
819
        self.addCleanup(state.unlock)
818
 
        state.add('a', 'a-id', 'file', None, '')
819
 
        entry = state._get_entry(0, path_utf8='a')
 
820
        state.add('a', b'a-id', 'file', None, b'')
 
821
        entry = state._get_entry(0, path_utf8=b'a')
820
822
        return state, entry
821
823
 
822
824
    def test_observed_sha1_cachable(self):
828
830
        statvalue.st_mtime = statvalue.st_ctime = atime
829
831
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
830
832
                         state._dirblock_state)
831
 
        state._observed_sha1(entry, "foo", statvalue)
832
 
        self.assertEqual('foo', entry[1][0][1])
 
833
        state._observed_sha1(entry, b"foo", statvalue)
 
834
        self.assertEqual(b'foo', entry[1][0][1])
833
835
        packed_stat = dirstate.pack_stat(statvalue)
834
836
        self.assertEqual(packed_stat, entry[1][0][4])
835
837
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
856
858
        tree.lock_write()
857
859
        empty_revid = tree.commit('empty')
858
860
        self.build_tree(['tree/a'])
859
 
        tree.add(['a'], ['a-id'])
 
861
        tree.add(['a'], [b'a-id'])
860
862
        with_a_id = tree.commit('with_a')
861
863
        self.addCleanup(tree.unlock)
862
864
        state.set_parent_trees(
863
865
            [(empty_revid, tree.branch.repository.revision_tree(empty_revid))],
864
866
            [])
865
 
        entry = state._get_entry(0, path_utf8='a')
 
867
        entry = state._get_entry(0, path_utf8=b'a')
866
868
        self.build_tree(['a'])
867
869
        # Add one where we don't provide the stat or sha already
868
 
        self.assertEqual(('', 'a', 'a-id'), entry[0])
869
 
        self.assertEqual(('f', '', 0, False, dirstate.DirState.NULLSTAT),
 
870
        self.assertEqual((b'', b'a', b'a-id'), entry[0])
 
871
        self.assertEqual((b'f', b'', 0, False, dirstate.DirState.NULLSTAT),
870
872
                         entry[1][0])
871
873
        # Flush the buffers to disk
872
874
        state.save()
875
877
 
876
878
        stat_value = os.lstat('a')
877
879
        packed_stat = dirstate.pack_stat(stat_value)
878
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
879
 
                                          stat_value=stat_value)
 
880
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
881
                                         stat_value=stat_value)
880
882
        self.assertEqual(None, link_or_sha1)
881
883
 
882
884
        # The dirblock entry should not have computed or cached the file's
883
885
        # sha1, but it did update the files' st_size. However, this is not
884
886
        # worth writing a dirstate file for, so we leave the state UNMODIFIED
885
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
887
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
886
888
                         entry[1][0])
887
889
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
888
890
                         state._dirblock_state)
898
900
        state.adjust_time(-10)
899
901
        del state._log[:]
900
902
 
901
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
902
 
                                          stat_value=stat_value)
 
903
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
904
                                         stat_value=stat_value)
903
905
        self.assertEqual([('is_exec', mode, False)], state._log)
904
906
        self.assertEqual(None, link_or_sha1)
905
907
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
906
908
                         state._dirblock_state)
907
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
909
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
908
910
                         entry[1][0])
909
911
        state.save()
910
912
 
912
914
        # won't calculate the sha or cache it.
913
915
        state.adjust_time(+20)
914
916
        del state._log[:]
915
 
        link_or_sha1 = dirstate.update_entry(state, entry, abspath='a',
916
 
                                          stat_value=stat_value)
 
917
        link_or_sha1 = dirstate.update_entry(state, entry, abspath=b'a',
 
918
                                             stat_value=stat_value)
917
919
        self.assertEqual(None, link_or_sha1)
918
920
        self.assertEqual([('is_exec', mode, False)], state._log)
919
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
921
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
920
922
                         entry[1][0])
921
923
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
922
924
                         state._dirblock_state)
927
929
        state.set_parent_trees(
928
930
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
929
931
            [])
930
 
        entry = state._get_entry(0, path_utf8='a')
 
932
        entry = state._get_entry(0, path_utf8=b'a')
931
933
 
932
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
933
 
                                          stat_value=stat_value)
934
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
934
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
935
                                         stat_value=stat_value)
 
936
        self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
935
937
                         link_or_sha1)
936
 
        self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
937
 
                          state._log)
938
 
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
938
        self.assertEqual([('is_exec', mode, False), ('sha1', b'a')],
 
939
                         state._log)
 
940
        self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
939
941
                         entry[1][0])
940
942
 
941
943
        # Subsequent calls will just return the cached value
942
944
        del state._log[:]
943
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
944
 
                                          stat_value=stat_value)
945
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
945
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
946
                                         stat_value=stat_value)
 
947
        self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
946
948
                         link_or_sha1)
947
949
        self.assertEqual([], state._log)
948
 
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
950
        self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
949
951
                         entry[1][0])
950
952
 
951
953
    def test_update_entry_symlink(self):
957
959
                         state._dirblock_state)
958
960
        os.symlink('target', 'a')
959
961
 
960
 
        state.adjust_time(-10) # Make the symlink look new
 
962
        state.adjust_time(-10)  # Make the symlink look new
961
963
        stat_value = os.lstat('a')
962
964
        packed_stat = dirstate.pack_stat(stat_value)
963
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
964
 
                                          stat_value=stat_value)
965
 
        self.assertEqual('target', link_or_sha1)
966
 
        self.assertEqual([('read_link', 'a', '')], state._log)
 
965
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
966
                                         stat_value=stat_value)
 
967
        self.assertEqual(b'target', link_or_sha1)
 
968
        self.assertEqual([('read_link', b'a', b'')], state._log)
967
969
        # Dirblock is not updated (the link is too new)
968
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
970
        self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
969
971
                         entry[1])
970
972
        # The file entry turned into a symlink, that is considered
971
973
        # HASH modified worthy.
974
976
 
975
977
        # Because the stat_value looks new, we should re-read the target
976
978
        del state._log[:]
977
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
978
 
                                          stat_value=stat_value)
979
 
        self.assertEqual('target', link_or_sha1)
980
 
        self.assertEqual([('read_link', 'a', '')], state._log)
981
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
979
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
980
                                         stat_value=stat_value)
 
981
        self.assertEqual(b'target', link_or_sha1)
 
982
        self.assertEqual([('read_link', b'a', b'')], state._log)
 
983
        self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
982
984
                         entry[1])
983
985
        state.save()
984
 
        state.adjust_time(+20) # Skip into the future, all files look old
 
986
        state.adjust_time(+20)  # Skip into the future, all files look old
985
987
        del state._log[:]
986
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
987
 
                                          stat_value=stat_value)
 
988
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
989
                                         stat_value=stat_value)
988
990
        # The symlink stayed a symlink. So while it is new enough to cache, we
989
991
        # don't bother setting the flag, because it is not really worth saving
990
992
        # (when we stat the symlink, we'll have paged in the target.)
991
993
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
992
994
                         state._dirblock_state)
993
 
        self.assertEqual('target', link_or_sha1)
 
995
        self.assertEqual(b'target', link_or_sha1)
994
996
        # We need to re-read the link because only now can we cache it
995
 
        self.assertEqual([('read_link', 'a', '')], state._log)
996
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
997
        self.assertEqual([('read_link', b'a', b'')], state._log)
 
998
        self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
997
999
                         entry[1])
998
1000
 
999
1001
        del state._log[:]
1000
1002
        # Another call won't re-read the link
1001
1003
        self.assertEqual([], state._log)
1002
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1003
 
                                          stat_value=stat_value)
1004
 
        self.assertEqual('target', link_or_sha1)
1005
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
1004
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
 
1005
                                         stat_value=stat_value)
 
1006
        self.assertEqual(b'target', link_or_sha1)
 
1007
        self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1006
1008
                         entry[1])
1007
1009
 
1008
1010
    def do_update_entry(self, state, entry, abspath):
1012
1014
    def test_update_entry_dir(self):
1013
1015
        state, entry = self.get_state_with_a()
1014
1016
        self.build_tree(['a/'])
1015
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1017
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
1016
1018
 
1017
1019
    def test_update_entry_dir_unchanged(self):
1018
1020
        state, entry = self.get_state_with_a()
1019
1021
        self.build_tree(['a/'])
1020
1022
        state.adjust_time(+20)
1021
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1023
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
1022
1024
        # a/ used to be a file, but is now a directory, worth saving
1023
1025
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1024
1026
                         state._dirblock_state)
1026
1028
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1027
1029
                         state._dirblock_state)
1028
1030
        # No changes to a/ means not worth saving.
1029
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1031
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
1030
1032
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1031
1033
                         state._dirblock_state)
1032
1034
        # Change the last-modified time for the directory
1037
1039
            # It looks like Win32 + FAT doesn't allow to change times on a dir.
1038
1040
            raise tests.TestSkipped("can't update mtime of a dir on FAT")
1039
1041
        saved_packed_stat = entry[1][0][-1]
1040
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1042
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
1041
1043
        # We *do* go ahead and update the information in the dirblocks, but we
1042
1044
        # don't bother setting IN_MEMORY_MODIFIED because it is trivial to
1043
1045
        # recompute.
1050
1052
        tree = self.make_branch_and_tree('tree')
1051
1053
        tree.lock_write()
1052
1054
        self.build_tree(['tree/a'])
1053
 
        tree.add(['a'], ['a-id'])
 
1055
        tree.add(['a'], [b'a-id'])
1054
1056
        with_a_id = tree.commit('witha')
1055
1057
        self.addCleanup(tree.unlock)
1056
1058
        state.set_parent_trees(
1057
1059
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
1058
1060
            [])
1059
 
        entry = state._get_entry(0, path_utf8='a')
 
1061
        entry = state._get_entry(0, path_utf8=b'a')
1060
1062
        self.build_tree(['a'])
1061
 
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1063
        sha1sum = b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1062
1064
        state.adjust_time(+20)
1063
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1065
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, b'a'))
1064
1066
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1065
1067
                         state._dirblock_state)
1066
1068
        state.save()
1067
1069
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1068
1070
                         state._dirblock_state)
1069
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1071
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, b'a'))
1070
1072
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1071
1073
                         state._dirblock_state)
1072
1074
 
1073
1075
    def test_update_entry_tree_reference(self):
1074
1076
        state = test_dirstate.InstrumentedDirState.initialize('dirstate')
1075
1077
        self.addCleanup(state.unlock)
1076
 
        state.add('r', 'r-id', 'tree-reference', None, '')
 
1078
        state.add('r', b'r-id', 'tree-reference', None, b'')
1077
1079
        self.build_tree(['r/'])
1078
 
        entry = state._get_entry(0, path_utf8='r')
 
1080
        entry = state._get_entry(0, path_utf8=b'r')
1079
1081
        self.do_update_entry(state, entry, 'r')
1080
 
        entry = state._get_entry(0, path_utf8='r')
1081
 
        self.assertEqual('t', entry[1][0][0])
 
1082
        entry = state._get_entry(0, path_utf8=b'r')
 
1083
        self.assertEqual(b't', entry[1][0][0])
1082
1084
 
1083
1085
    def create_and_test_file(self, state, entry):
1084
1086
        """Create a file at 'a' and verify the state finds it during update.
1092
1094
 
1093
1095
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1094
1096
        self.assertEqual(None, link_or_sha1)
1095
 
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
 
1097
        self.assertEqual([(b'f', b'', 14, False, dirstate.DirState.NULLSTAT)],
1096
1098
                         entry[1])
1097
1099
        return packed_stat
1098
1100
 
1106
1108
        stat_value = os.lstat('a')
1107
1109
        packed_stat = dirstate.pack_stat(stat_value)
1108
1110
 
1109
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1111
        link_or_sha1 = self.do_update_entry(state, entry, abspath=b'a')
1110
1112
        self.assertIs(None, link_or_sha1)
1111
 
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
 
1113
        self.assertEqual([(b'd', b'', 0, False, packed_stat)], entry[1])
1112
1114
 
1113
1115
        return packed_stat
1114
1116
 
1128
1130
        stat_value = os.lstat('a')
1129
1131
        packed_stat = dirstate.pack_stat(stat_value)
1130
1132
 
1131
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1132
 
        self.assertEqual('path/to/foo', link_or_sha1)
1133
 
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
 
1133
        link_or_sha1 = self.do_update_entry(state, entry, abspath=b'a')
 
1134
        self.assertEqual(b'path/to/foo', link_or_sha1)
 
1135
        self.assertEqual([(b'l', b'path/to/foo', 11, False, packed_stat)],
1134
1136
                         entry[1])
1135
1137
        return packed_stat
1136
1138
 
1198
1200
        state, entry = self.get_state_with_a()
1199
1201
        self.build_tree(['a'])
1200
1202
 
1201
 
        # Make sure we are using the win32 implementation of _is_executable
1202
 
        state._is_executable = state._is_executable_win32
 
1203
        # Make sure we are using the version of _is_executable that doesn't
 
1204
        # check the filesystem mode.
 
1205
        state._use_filesystem_for_exec = False
1203
1206
 
1204
1207
        # The file on disk is not executable, but we are marking it as though
1205
 
        # it is. With _is_executable_win32 we ignore what is on disk.
1206
 
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
 
1208
        # it is. With _use_filesystem_for_exec disabled we ignore what is on
 
1209
        # disk.
 
1210
        entry[1][0] = (b'f', b'', 0, True, dirstate.DirState.NULLSTAT)
1207
1211
 
1208
1212
        stat_value = os.lstat('a')
1209
1213
        packed_stat = dirstate.pack_stat(stat_value)
1210
1214
 
1211
 
        state.adjust_time(-10) # Make sure everything is new
1212
 
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
 
1215
        state.adjust_time(-10)  # Make sure everything is new
 
1216
        self.update_entry(state, entry, abspath=b'a', stat_value=stat_value)
1213
1217
 
1214
1218
        # The row is updated, but the executable bit stays set.
1215
 
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1219
        self.assertEqual([(b'f', b'', 14, True, dirstate.DirState.NULLSTAT)],
1216
1220
                         entry[1])
1217
1221
 
1218
1222
        # Make the disk object look old enough to cache (but it won't cache the
1219
1223
        # sha as it is a new file).
1220
1224
        state.adjust_time(+20)
1221
 
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1222
 
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1223
 
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1224
 
            entry[1])
 
1225
        digest = b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1226
        self.update_entry(state, entry, abspath=b'a', stat_value=stat_value)
 
1227
        self.assertEqual([(b'f', b'', 14, True, dirstate.DirState.NULLSTAT)],
 
1228
                         entry[1])
1225
1229
 
1226
1230
    def _prepare_tree(self):
1227
1231
        # Create a tree
1228
 
        text = 'Hello World\n'
 
1232
        text = b'Hello World\n'
1229
1233
        tree = self.make_branch_and_tree('tree')
1230
1234
        self.build_tree_contents([('tree/a file', text)])
1231
 
        tree.add('a file', 'a-file-id')
 
1235
        tree.add('a file', b'a-file-id')
1232
1236
        # Note: dirstate does not sha prior to the first commit
1233
1237
        # so commit now in order for the test to work
1234
1238
        tree.commit('first')
1237
1241
    def test_sha1provider_sha1_used(self):
1238
1242
        tree, text = self._prepare_tree()
1239
1243
        state = dirstate.DirState.from_tree(tree, 'dirstate',
1240
 
            UppercaseSHA1Provider())
 
1244
                                            UppercaseSHA1Provider())
1241
1245
        self.addCleanup(state.unlock)
1242
 
        expected_sha = osutils.sha_string(text.upper() + "foo")
1243
 
        entry = state._get_entry(0, path_utf8='a file')
 
1246
        expected_sha = osutils.sha_string(text.upper() + b"foo")
 
1247
        entry = state._get_entry(0, path_utf8=b'a file')
 
1248
        self.assertNotEqual((None, None), entry)
1244
1249
        state._sha_cutoff_time()
1245
1250
        state._cutoff_time += 10
1246
1251
        sha1 = self.update_entry(state, entry, 'tree/a file',
1255
1260
        state._sha1_provider = UppercaseSHA1Provider()
1256
1261
        # If we used the standard provider, it would look like nothing has
1257
1262
        # changed
1258
 
        file_ids_changed = [change[0] for change
 
1263
        file_ids_changed = [change.file_id for change
1259
1264
                            in tree.iter_changes(tree.basis_tree())]
1260
 
        self.assertEqual(['a-file-id'], file_ids_changed)
 
1265
        self.assertEqual([b'a-file-id'], file_ids_changed)
1261
1266
 
1262
1267
 
1263
1268
class UppercaseSHA1Provider(dirstate.SHA1Provider):
1267
1272
        return self.stat_and_sha1(abspath)[1]
1268
1273
 
1269
1274
    def stat_and_sha1(self, abspath):
1270
 
        file_obj = file(abspath, 'rb')
1271
 
        try:
 
1275
        with open(abspath, 'rb') as file_obj:
1272
1276
            statvalue = os.fstat(file_obj.fileno())
1273
 
            text = ''.join(file_obj.readlines())
1274
 
            sha1 = osutils.sha_string(text.upper() + "foo")
1275
 
        finally:
1276
 
            file_obj.close()
 
1277
            text = b''.join(file_obj.readlines())
 
1278
            sha1 = osutils.sha_string(text.upper() + b"foo")
1277
1279
        return statvalue, sha1
1278
1280
 
1279
1281
 
1289
1291
        self.overrideAttr(dirstate, '_process_entry', self._process_entry)
1290
1292
 
1291
1293
    def assertChangedFileIds(self, expected, tree):
1292
 
        tree.lock_read()
1293
 
        try:
1294
 
            file_ids = [info[0] for info
 
1294
        with tree.lock_read():
 
1295
            file_ids = [info.file_id for info
1295
1296
                        in tree.iter_changes(tree.basis_tree())]
1296
 
        finally:
1297
 
            tree.unlock()
1298
1297
        self.assertEqual(sorted(expected), sorted(file_ids))
1299
1298
 
1300
1299
    def test_exceptions_raised(self):
1309
1308
        tree.lock_read()
1310
1309
        self.addCleanup(tree.unlock)
1311
1310
        basis_tree = tree.basis_tree()
 
1311
 
1312
1312
        def is_inside_raises(*args, **kwargs):
1313
1313
            raise RuntimeError('stop this')
 
1314
        self.overrideAttr(dirstate, 'is_inside', is_inside_raises)
 
1315
        try:
 
1316
            from breezy.bzr import _dirstate_helpers_pyx
 
1317
        except ImportError:
 
1318
            pass
 
1319
        else:
 
1320
            self.overrideAttr(_dirstate_helpers_pyx,
 
1321
                              'is_inside', is_inside_raises)
1314
1322
        self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1315
1323
        self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1316
1324
 
1317
1325
    def test_simple_changes(self):
1318
1326
        tree = self.make_branch_and_tree('tree')
1319
1327
        self.build_tree(['tree/file'])
1320
 
        tree.add(['file'], ['file-id'])
1321
 
        self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
 
1328
        tree.add(['file'], [b'file-id'])
 
1329
        self.assertChangedFileIds([tree.path2id(''), b'file-id'], tree)
1322
1330
        tree.commit('one')
1323
1331
        self.assertChangedFileIds([], tree)
1324
1332
 
1325
1333
    def test_sha1provider_stat_and_sha1_used(self):
1326
1334
        tree = self.make_branch_and_tree('tree')
1327
1335
        self.build_tree(['tree/file'])
1328
 
        tree.add(['file'], ['file-id'])
 
1336
        tree.add(['file'], [b'file-id'])
1329
1337
        tree.commit('one')
1330
1338
        tree.lock_write()
1331
1339
        self.addCleanup(tree.unlock)
1332
1340
        state = tree._current_dirstate()
1333
1341
        state._sha1_provider = UppercaseSHA1Provider()
1334
 
        self.assertChangedFileIds(['file-id'], tree)
 
1342
        self.assertChangedFileIds([b'file-id'], tree)
1335
1343
 
1336
1344
 
1337
1345
class TestPackStat(tests.TestCase):
1347
1355
        return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
1348
1356
 
1349
1357
    def test_result(self):
1350
 
        self.assertEqual("AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
1351
 
            self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
 
1358
        self.assertEqual(b"AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
 
1359
                         self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
1352
1360
 
1353
1361
    def test_giant_inode(self):
1354
1362
        packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))