29
from bzrlib.tests import (
35
from bzrlib import _dirstate_helpers_pyx
36
has_dirstate_helpers_pyx = True
38
has_dirstate_helpers_pyx = False
41
compiled_dirstate_helpers_feature = tests.ModuleAvailableFeature(
42
'bzrlib._dirstate_helpers_pyx')
45
def load_tests(basic_tests, module, loader):
46
# FIXME: we should also parametrize against SHA1Provider !
47
suite = loader.suiteClass()
48
remaining_tests = basic_tests
50
dir_reader_scenarios = test_osutils.dir_reader_scenarios()
52
ue_scenarios = [('dirstate_Python',
53
{'update_entry': dirstate.py_update_entry})]
54
if compiled_dirstate_helpers_feature.available():
55
update_entry = compiled_dirstate_helpers_feature.module.update_entry
56
pyrex_scenario = ('dirstate_Pyrex', {'update_entry': update_entry})
57
ue_scenarios.append(pyrex_scenario)
58
process_entry_tests, remaining_tests = tests.split_suite_by_condition(
59
remaining_tests, tests.condition_isinstance(TestUpdateEntry))
60
tests.multiply_tests(process_entry_tests,
61
tests.multiply_scenarios(dir_reader_scenarios,
65
pe_scenarios = [('dirstate_Python',
66
{'_process_entry': dirstate.ProcessEntryPython})]
67
if compiled_dirstate_helpers_feature.available():
68
process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
69
pyrex_scenario = ('dirstate_Pyrex', {'_process_entry': process_entry})
70
pe_scenarios.append(pyrex_scenario)
71
process_entry_tests, remaining_tests = tests.split_suite_by_condition(
72
remaining_tests, tests.condition_isinstance(TestProcessEntry))
73
tests.multiply_tests(process_entry_tests,
74
tests.multiply_scenarios(dir_reader_scenarios,
78
dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
79
remaining_tests, tests.condition_isinstance(
80
test_dirstate.TestCaseWithDirState))
81
tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
82
suite.addTest(remaining_tests)
34
from .test_osutils import dir_reader_scenarios
35
from .scenarios import (
36
load_tests_apply_scenarios,
44
load_tests = load_tests_apply_scenarios
47
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
48
'breezy.bzr._dirstate_helpers_pyx')
51
# FIXME: we should also parametrize against SHA1Provider !
53
ue_scenarios = [('dirstate_Python',
54
{'update_entry': dirstate.py_update_entry})]
55
if compiled_dirstate_helpers_feature.available():
56
update_entry = compiled_dirstate_helpers_feature.module.update_entry
57
ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
59
pe_scenarios = [('dirstate_Python',
60
{'_process_entry': dirstate.ProcessEntryPython})]
61
if compiled_dirstate_helpers_feature.available():
62
process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
63
pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
65
helper_scenarios = [('dirstate_Python', {'helpers': _dirstate_helpers_py})]
66
if compiled_dirstate_helpers_feature.available():
67
helper_scenarios.append(('dirstate_Pyrex',
68
{'helpers': compiled_dirstate_helpers_feature.module}))
87
71
class TestBisectPathMixin(object):
142
126
dir_split_paths = []
143
127
for path in paths:
144
128
dirname, basename = os.path.split(path)
145
dir_split_paths.append((dirname.split('/'), basename))
129
dir_split_paths.append((dirname.split(b'/'), basename))
146
130
dir_split_paths.sort()
147
131
return dir_split_paths
149
133
def test_simple(self):
150
134
"""In the simple case it works just like bisect_left"""
151
paths = ['', 'a', 'b', 'c', 'd']
135
paths = [b'', b'a', b'b', b'c', b'd']
152
136
split_paths = self.split_for_dirblocks(paths)
153
137
for path in paths:
154
138
self.assertBisect(paths, split_paths, path, exists=True)
155
self.assertBisect(paths, split_paths, '_', exists=False)
156
self.assertBisect(paths, split_paths, 'aa', exists=False)
157
self.assertBisect(paths, split_paths, 'bb', exists=False)
158
self.assertBisect(paths, split_paths, 'cc', exists=False)
159
self.assertBisect(paths, split_paths, 'dd', exists=False)
160
self.assertBisect(paths, split_paths, 'a/a', exists=False)
161
self.assertBisect(paths, split_paths, 'b/b', exists=False)
162
self.assertBisect(paths, split_paths, 'c/c', exists=False)
163
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)
165
149
def test_involved(self):
166
150
"""This is where bisect_path_* diverges slightly."""
325
309
Also, ensure that the paths are in proper sorted order.
327
311
dirblocks = [(path, []) for path in paths]
328
split_dirblocks = [(path.split('/'), []) for path in paths]
312
split_dirblocks = [(path.split(b'/'), []) for path in paths]
329
313
self.assertEqual(sorted(split_dirblocks), split_dirblocks)
330
314
return dirblocks, split_dirblocks
332
316
def test_simple(self):
333
317
"""In the simple case it works just like bisect_left"""
334
paths = ['', 'a', 'b', 'c', 'd']
318
paths = [b'', b'a', b'b', b'c', b'd']
335
319
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
336
320
for path in paths:
337
321
self.assertBisect(dirblocks, split_dirblocks, path)
338
self.assertBisect(dirblocks, split_dirblocks, '_')
339
self.assertBisect(dirblocks, split_dirblocks, 'aa')
340
self.assertBisect(dirblocks, split_dirblocks, 'bb')
341
self.assertBisect(dirblocks, split_dirblocks, 'cc')
342
self.assertBisect(dirblocks, split_dirblocks, 'dd')
343
self.assertBisect(dirblocks, split_dirblocks, 'a/a')
344
self.assertBisect(dirblocks, split_dirblocks, 'b/b')
345
self.assertBisect(dirblocks, split_dirblocks, 'c/c')
346
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')
348
332
def test_involved(self):
349
333
"""This is where bisect_left diverges slightly."""
351
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
352
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
354
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
355
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
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',
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',
358
342
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
359
343
for path in paths:
416
400
:param str1: string to compare
417
401
:param str2: string to compare
419
cmp_by_dirs = self.get_cmp_by_dirs()
403
lt_by_dirs = self.get_lt_by_dirs()
420
404
if expected == 0:
421
405
self.assertEqual(str1, str2)
422
self.assertEqual(0, cmp_by_dirs(str1, str2))
423
self.assertEqual(0, cmp_by_dirs(str2, str1))
406
self.assertFalse(lt_by_dirs(str1, str2))
407
self.assertFalse(lt_by_dirs(str2, str1))
424
408
elif expected > 0:
425
self.assertPositive(cmp_by_dirs(str1, str2))
426
self.assertNegative(cmp_by_dirs(str2, str1))
409
self.assertFalse(lt_by_dirs(str1, str2))
410
self.assertTrue(lt_by_dirs(str2, str1))
428
self.assertNegative(cmp_by_dirs(str1, str2))
429
self.assertPositive(cmp_by_dirs(str2, str1))
412
self.assertTrue(lt_by_dirs(str1, str2))
413
self.assertFalse(lt_by_dirs(str2, str1))
431
415
def test_cmp_empty(self):
432
416
"""Compare against the empty string."""
433
self.assertCmpByDirs(0, '', '')
434
self.assertCmpByDirs(1, 'a', '')
435
self.assertCmpByDirs(1, 'ab', '')
436
self.assertCmpByDirs(1, 'abc', '')
437
self.assertCmpByDirs(1, 'abcd', '')
438
self.assertCmpByDirs(1, 'abcde', '')
439
self.assertCmpByDirs(1, 'abcdef', '')
440
self.assertCmpByDirs(1, 'abcdefg', '')
441
self.assertCmpByDirs(1, 'abcdefgh', '')
442
self.assertCmpByDirs(1, 'abcdefghi', '')
443
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'')
445
429
def test_cmp_same_str(self):
446
430
"""Compare the same string"""
447
self.assertCmpByDirs(0, 'a', 'a')
448
self.assertCmpByDirs(0, 'ab', 'ab')
449
self.assertCmpByDirs(0, 'abc', 'abc')
450
self.assertCmpByDirs(0, 'abcd', 'abcd')
451
self.assertCmpByDirs(0, 'abcde', 'abcde')
452
self.assertCmpByDirs(0, 'abcdef', 'abcdef')
453
self.assertCmpByDirs(0, 'abcdefg', 'abcdefg')
454
self.assertCmpByDirs(0, 'abcdefgh', 'abcdefgh')
455
self.assertCmpByDirs(0, 'abcdefghi', 'abcdefghi')
456
self.assertCmpByDirs(0, 'testing a long string', 'testing a long string')
457
self.assertCmpByDirs(0, 'x'*10000, 'x'*10000)
458
self.assertCmpByDirs(0, 'a/b', 'a/b')
459
self.assertCmpByDirs(0, 'a/b/c', 'a/b/c')
460
self.assertCmpByDirs(0, 'a/b/c/d', 'a/b/c/d')
461
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', b'testing a long string')
441
self.assertCmpByDirs(0, b'x'*10000, b'x'*10000)
442
self.assertCmpByDirs(0, b'a/b', b'a/b')
443
self.assertCmpByDirs(0, b'a/b/c', b'a/b/c')
444
self.assertCmpByDirs(0, b'a/b/c/d', b'a/b/c/d')
445
self.assertCmpByDirs(0, b'a/b/c/d/e', b'a/b/c/d/e')
463
447
def test_simple_paths(self):
464
448
"""Compare strings that act like normal string comparison"""
465
self.assertCmpByDirs(-1, 'a', 'b')
466
self.assertCmpByDirs(-1, 'aa', 'ab')
467
self.assertCmpByDirs(-1, 'ab', 'bb')
468
self.assertCmpByDirs(-1, 'aaa', 'aab')
469
self.assertCmpByDirs(-1, 'aab', 'abb')
470
self.assertCmpByDirs(-1, 'abb', 'bbb')
471
self.assertCmpByDirs(-1, 'aaaa', 'aaab')
472
self.assertCmpByDirs(-1, 'aaab', 'aabb')
473
self.assertCmpByDirs(-1, 'aabb', 'abbb')
474
self.assertCmpByDirs(-1, 'abbb', 'bbbb')
475
self.assertCmpByDirs(-1, 'aaaaa', 'aaaab')
476
self.assertCmpByDirs(-1, 'a/a', 'a/b')
477
self.assertCmpByDirs(-1, 'a/b', 'b/b')
478
self.assertCmpByDirs(-1, 'a/a/a', 'a/a/b')
479
self.assertCmpByDirs(-1, 'a/a/b', 'a/b/b')
480
self.assertCmpByDirs(-1, 'a/b/b', 'b/b/b')
481
self.assertCmpByDirs(-1, 'a/a/a/a', 'a/a/a/b')
482
self.assertCmpByDirs(-1, 'a/a/a/b', 'a/a/b/b')
483
self.assertCmpByDirs(-1, 'a/a/b/b', 'a/b/b/b')
484
self.assertCmpByDirs(-1, 'a/b/b/b', 'b/b/b/b')
485
self.assertCmpByDirs(-1, 'a/a/a/a/a', 'a/a/a/a/b')
449
self.assertCmpByDirs(-1, b'a', b'b')
450
self.assertCmpByDirs(-1, b'aa', b'ab')
451
self.assertCmpByDirs(-1, b'ab', b'bb')
452
self.assertCmpByDirs(-1, b'aaa', b'aab')
453
self.assertCmpByDirs(-1, b'aab', b'abb')
454
self.assertCmpByDirs(-1, b'abb', b'bbb')
455
self.assertCmpByDirs(-1, b'aaaa', b'aaab')
456
self.assertCmpByDirs(-1, b'aaab', b'aabb')
457
self.assertCmpByDirs(-1, b'aabb', b'abbb')
458
self.assertCmpByDirs(-1, b'abbb', b'bbbb')
459
self.assertCmpByDirs(-1, b'aaaaa', b'aaaab')
460
self.assertCmpByDirs(-1, b'a/a', b'a/b')
461
self.assertCmpByDirs(-1, b'a/b', b'b/b')
462
self.assertCmpByDirs(-1, b'a/a/a', b'a/a/b')
463
self.assertCmpByDirs(-1, b'a/a/b', b'a/b/b')
464
self.assertCmpByDirs(-1, b'a/b/b', b'b/b/b')
465
self.assertCmpByDirs(-1, b'a/a/a/a', b'a/a/a/b')
466
self.assertCmpByDirs(-1, b'a/a/a/b', b'a/a/b/b')
467
self.assertCmpByDirs(-1, b'a/a/b/b', b'a/b/b/b')
468
self.assertCmpByDirs(-1, b'a/b/b/b', b'b/b/b/b')
469
self.assertCmpByDirs(-1, b'a/a/a/a/a', b'a/a/a/a/b')
487
471
def test_tricky_paths(self):
488
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/cc/ef')
489
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/c/ef')
490
self.assertCmpByDirs(-1, 'ab/cd/ef', 'ab/cd-ef')
491
self.assertCmpByDirs(-1, 'ab/cd', 'ab/cd-')
492
self.assertCmpByDirs(-1, 'ab/cd', 'ab-cd')
472
self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/cc/ef')
473
self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/c/ef')
474
self.assertCmpByDirs(-1, b'ab/cd/ef', b'ab/cd-ef')
475
self.assertCmpByDirs(-1, b'ab/cd', b'ab/cd-')
476
self.assertCmpByDirs(-1, b'ab/cd', b'ab-cd')
494
478
def test_cmp_unicode_not_allowed(self):
495
cmp_by_dirs = self.get_cmp_by_dirs()
496
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', 'str')
497
self.assertRaises(TypeError, cmp_by_dirs, 'str', u'Unicode')
498
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', u'Unicode')
479
lt_by_dirs = self.get_lt_by_dirs()
480
self.assertRaises(TypeError, lt_by_dirs, u'Unicode', b'str')
481
self.assertRaises(TypeError, lt_by_dirs, b'str', u'Unicode')
482
self.assertRaises(TypeError, lt_by_dirs, u'Unicode', u'Unicode')
500
484
def test_cmp_non_ascii(self):
501
self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
502
self.assertCmpByDirs(-1, 'a', '\xc3\xa5') # u'a', u'\xe5'
503
self.assertCmpByDirs(-1, 'b', '\xc2\xb5') # u'b', u'\xb5'
504
self.assertCmpByDirs(-1, 'a/b', 'a/\xc3\xa5') # u'a/b', u'a/\xe5'
505
self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
508
class TestCompiledCmpByDirs(TestCmpByDirs):
509
"""Test the pyrex implementation of cmp_by_dirs"""
485
self.assertCmpByDirs(-1, b'\xc2\xb5', b'\xc3\xa5') # u'\xb5', u'\xe5'
486
self.assertCmpByDirs(-1, b'a', b'\xc3\xa5') # u'a', u'\xe5'
487
self.assertCmpByDirs(-1, b'b', b'\xc2\xb5') # u'b', u'\xb5'
488
self.assertCmpByDirs(-1, b'a/b', b'a/\xc3\xa5') # u'a/b', u'a/\xe5'
489
self.assertCmpByDirs(-1, b'b/a', b'b/\xc2\xb5') # u'b/a', u'b/\xb5'
492
class TestCompiledLtByDirs(TestLtByDirs):
493
"""Test the pyrex implementation of lt_by_dirs"""
511
495
_test_needs_features = [compiled_dirstate_helpers_feature]
513
def get_cmp_by_dirs(self):
514
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
518
class TestCmpPathByDirblock(tests.TestCase):
519
"""Test an implementation of _cmp_path_by_dirblock()
521
_cmp_path_by_dirblock() compares two paths using the sort order used by
497
def get_lt_by_dirs(self):
498
from ..bzr._dirstate_helpers_pyx import lt_by_dirs
502
class TestLtPathByDirblock(tests.TestCase):
503
"""Test an implementation of _lt_path_by_dirblock()
505
_lt_path_by_dirblock() compares two paths using the sort order used by
522
506
DirState. All paths in the same directory are sorted together.
524
Child test cases can override ``get_cmp_path_by_dirblock`` to test a specific
508
Child test cases can override ``get_lt_path_by_dirblock`` to test a specific
528
def get_cmp_path_by_dirblock(self):
529
"""Get a specific implementation of _cmp_path_by_dirblock."""
530
from bzrlib._dirstate_helpers_py import _cmp_path_by_dirblock
531
return _cmp_path_by_dirblock
512
def get_lt_path_by_dirblock(self):
513
"""Get a specific implementation of _lt_path_by_dirblock."""
514
from ..bzr._dirstate_helpers_py import _lt_path_by_dirblock
515
return _lt_path_by_dirblock
533
def assertCmpPathByDirblock(self, paths):
517
def assertLtPathByDirblock(self, paths):
534
518
"""Compare all paths and make sure they evaluate to the correct order.
536
520
This does N^2 comparisons. It is assumed that ``paths`` is properly
541
525
# First, make sure the paths being passed in are correct
543
527
dirname, basename = os.path.split(p)
544
return dirname.split('/'), basename
528
return dirname.split(b'/'), basename
545
529
self.assertEqual(sorted(paths, key=_key), paths)
547
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
531
lt_path_by_dirblock = self.get_lt_path_by_dirblock()
548
532
for idx1, path1 in enumerate(paths):
549
533
for idx2, path2 in enumerate(paths):
550
cmp_val = cmp_path_by_dirblock(path1, path2)
552
self.assertTrue(cmp_val < 0,
553
'%s did not state that %r came before %r, cmp=%s'
554
% (cmp_path_by_dirblock.__name__,
555
path1, path2, cmp_val))
557
self.assertTrue(cmp_val > 0,
558
'%s did not state that %r came after %r, cmp=%s'
559
% (cmp_path_by_dirblock.__name__,
560
path1, path2, cmp_val))
562
self.assertTrue(cmp_val == 0,
563
'%s did not state that %r == %r, cmp=%s'
564
% (cmp_path_by_dirblock.__name__,
565
path1, path2, cmp_val))
534
lt_result = lt_path_by_dirblock(path1, path2)
535
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))
567
540
def test_cmp_simple_paths(self):
568
541
"""Compare against the empty string."""
569
self.assertCmpPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
570
self.assertCmpPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
542
self.assertLtPathByDirblock([b'', b'a', b'ab', b'abc', b'a/b/c', b'b/d/e'])
543
self.assertLtPathByDirblock([b'kl', b'ab/cd', b'ab/ef', b'gh/ij'])
572
545
def test_tricky_paths(self):
573
self.assertCmpPathByDirblock([
546
self.assertLtPathByDirblock([
575
'', 'a', 'a-a', 'a=a', 'b',
548
b'', b'a', b'a-a', b'a=a', b'b',
576
549
# Contents of 'a'
577
'a/a', 'a/a-a', 'a/a=a', 'a/b',
550
b'a/a', b'a/a-a', b'a/a=a', b'a/b',
578
551
# Contents of 'a/a'
579
'a/a/a', 'a/a/a-a', 'a/a/a=a',
552
b'a/a/a', b'a/a/a-a', b'a/a/a=a',
580
553
# Contents of 'a/a/a'
581
'a/a/a/a', 'a/a/a/b',
554
b'a/a/a/a', b'a/a/a/b',
582
555
# Contents of 'a/a/a-a',
583
'a/a/a-a/a', 'a/a/a-a/b',
556
b'a/a/a-a/a', b'a/a/a-a/b',
584
557
# Contents of 'a/a/a=a',
585
'a/a/a=a/a', 'a/a/a=a/b',
558
b'a/a/a=a/a', b'a/a/a=a/b',
586
559
# Contents of 'a/a-a'
588
561
# Contents of 'a/a-a/a'
589
'a/a-a/a/a', 'a/a-a/a/b',
562
b'a/a-a/a/a', b'a/a-a/a/b',
590
563
# Contents of 'a/a=a'
592
565
# Contents of 'a/b'
594
567
# Contents of 'a-a',
596
569
# Contents of 'a=a',
598
571
# Contents of 'b',
601
self.assertCmpPathByDirblock([
574
self.assertLtPathByDirblock([
603
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
576
b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
604
577
# content of 'a/'
605
'a/a', 'a/a-a', 'a/a-z',
607
'a/z', 'a/z-a', 'a/z-z',
578
b'a/a', b'a/a-a', b'a/a-z',
580
b'a/z', b'a/z-a', b'a/z-z',
609
582
# content of 'a/a/'
611
584
# content of 'a/a-a'
613
586
# content of 'a/a-z'
615
588
# content of 'a/a=a'
617
590
# content of 'a/a=z'
619
592
# content of 'a/z/'
621
594
# content of 'a-a'
623
596
# content of 'a-z'
625
598
# content of 'a=a'
627
600
# content of 'a=z'
631
604
def test_unicode_not_allowed(self):
632
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
633
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', 'str')
634
self.assertRaises(TypeError, cmp_path_by_dirblock, 'str', u'Uni')
635
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', u'Uni')
636
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', 'x/str')
637
self.assertRaises(TypeError, cmp_path_by_dirblock, 'x/str', u'x/Uni')
638
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', u'x/Uni')
605
lt_path_by_dirblock = self.get_lt_path_by_dirblock()
606
self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', 'str')
607
self.assertRaises(TypeError, lt_path_by_dirblock, 'str', u'Uni')
608
self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', u'Uni')
609
self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', 'x/str')
610
self.assertRaises(TypeError, lt_path_by_dirblock, 'x/str', u'x/Uni')
611
self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', u'x/Uni')
640
613
def test_nonascii(self):
641
self.assertCmpPathByDirblock([
614
self.assertLtPathByDirblock([
643
'', 'a', '\xc2\xb5', '\xc3\xa5',
616
b'', b'a', b'\xc2\xb5', b'\xc3\xa5',
645
'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
618
b'a/a', b'a/\xc2\xb5', b'a/\xc3\xa5',
646
619
# content of 'a/a'
647
'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
620
b'a/a/a', b'a/a/\xc2\xb5', b'a/a/\xc3\xa5',
648
621
# content of 'a/\xc2\xb5'
649
'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
622
b'a/\xc2\xb5/a', b'a/\xc2\xb5/\xc2\xb5', b'a/\xc2\xb5/\xc3\xa5',
650
623
# content of 'a/\xc3\xa5'
651
'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
624
b'a/\xc3\xa5/a', b'a/\xc3\xa5/\xc2\xb5', b'a/\xc3\xa5/\xc3\xa5',
652
625
# content of '\xc2\xb5'
653
'\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
626
b'\xc2\xb5/a', b'\xc2\xb5/\xc2\xb5', b'\xc2\xb5/\xc3\xa5',
654
627
# content of '\xc2\xe5'
655
'\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
628
b'\xc3\xa5/a', b'\xc3\xa5/\xc2\xb5', b'\xc3\xa5/\xc3\xa5',
659
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
660
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
632
class TestCompiledLtPathByDirblock(TestLtPathByDirblock):
633
"""Test the pyrex implementation of _lt_path_by_dirblock"""
662
635
_test_needs_features = [compiled_dirstate_helpers_feature]
664
def get_cmp_by_dirs(self):
665
from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
666
return _cmp_path_by_dirblock
637
def get_lt_path_by_dirblock(self):
638
from ..bzr._dirstate_helpers_pyx import _lt_path_by_dirblock
639
return _lt_path_by_dirblock
669
642
class TestMemRChr(tests.TestCase):
775
750
def test_bisect_dirblock(self):
776
751
if compiled_dirstate_helpers_feature.available():
777
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
752
from breezy.bzr._dirstate_helpers_pyx import bisect_dirblock
779
from bzrlib._dirstate_helpers_py import bisect_dirblock
754
from breezy.bzr._dirstate_helpers_py import bisect_dirblock
780
755
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
782
757
def test__bisect_path_left(self):
783
758
if compiled_dirstate_helpers_feature.available():
784
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
759
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_left
786
from bzrlib._dirstate_helpers_py import _bisect_path_left
761
from breezy.bzr._dirstate_helpers_py import _bisect_path_left
787
762
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
789
764
def test__bisect_path_right(self):
790
765
if compiled_dirstate_helpers_feature.available():
791
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
766
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_right
793
from bzrlib._dirstate_helpers_py import _bisect_path_right
768
from breezy.bzr._dirstate_helpers_py import _bisect_path_right
794
769
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
796
def test_cmp_by_dirs(self):
771
def test_lt_by_dirs(self):
797
772
if compiled_dirstate_helpers_feature.available():
798
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
773
from ..bzr._dirstate_helpers_pyx import lt_by_dirs
800
from bzrlib._dirstate_helpers_py import cmp_by_dirs
801
self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
775
from ..bzr._dirstate_helpers_py import lt_by_dirs
776
self.assertIs(lt_by_dirs, dirstate.lt_by_dirs)
803
778
def test__read_dirblocks(self):
804
779
if compiled_dirstate_helpers_feature.available():
805
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
780
from breezy.bzr._dirstate_helpers_pyx import _read_dirblocks
807
from bzrlib._dirstate_helpers_py import _read_dirblocks
782
from breezy.bzr._dirstate_helpers_py import _read_dirblocks
808
783
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
810
785
def test_update_entry(self):
811
786
if compiled_dirstate_helpers_feature.available():
812
from bzrlib._dirstate_helpers_pyx import update_entry
787
from breezy.bzr._dirstate_helpers_pyx import update_entry
814
from bzrlib.dirstate import update_entry
789
from breezy.bzr.dirstate import update_entry
815
790
self.assertIs(update_entry, dirstate.update_entry)
817
792
def test_process_entry(self):
818
793
if compiled_dirstate_helpers_feature.available():
819
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
794
from breezy.bzr._dirstate_helpers_pyx import ProcessEntryC
820
795
self.assertIs(ProcessEntryC, dirstate._process_entry)
822
from bzrlib.dirstate import ProcessEntryPython
797
from breezy.bzr.dirstate import ProcessEntryPython
823
798
self.assertIs(ProcessEntryPython, dirstate._process_entry)
826
801
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
827
802
"""Test the DirState.update_entry functions"""
804
scenarios = multiply_scenarios(
805
dir_reader_scenarios(), ue_scenarios)
829
807
# Set by load_tests
830
808
update_entry = None
970
960
state.adjust_time(-10) # Make the symlink look new
971
961
stat_value = os.lstat('a')
972
962
packed_stat = dirstate.pack_stat(stat_value)
973
link_or_sha1 = self.update_entry(state, entry, abspath='a',
963
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
974
964
stat_value=stat_value)
975
self.assertEqual('target', link_or_sha1)
976
self.assertEqual([('read_link', 'a', '')], state._log)
965
self.assertEqual(b'target', link_or_sha1)
966
self.assertEqual([('read_link', b'a', b'')], state._log)
977
967
# Dirblock is not updated (the link is too new)
978
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
968
self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
980
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
970
# The file entry turned into a symlink, that is considered
971
# HASH modified worthy.
972
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
981
973
state._dirblock_state)
983
975
# Because the stat_value looks new, we should re-read the target
984
link_or_sha1 = self.update_entry(state, entry, abspath='a',
977
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
985
978
stat_value=stat_value)
986
self.assertEqual('target', link_or_sha1)
987
self.assertEqual([('read_link', 'a', ''),
988
('read_link', 'a', ''),
990
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
979
self.assertEqual(b'target', link_or_sha1)
980
self.assertEqual([('read_link', b'a', b'')], state._log)
981
self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
992
984
state.adjust_time(+20) # Skip into the future, all files look old
993
link_or_sha1 = self.update_entry(state, entry, abspath='a',
986
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
994
987
stat_value=stat_value)
995
self.assertEqual('target', link_or_sha1)
988
# The symlink stayed a symlink. So while it is new enough to cache, we
989
# don't bother setting the flag, because it is not really worth saving
990
# (when we stat the symlink, we'll have paged in the target.)
991
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
992
state._dirblock_state)
993
self.assertEqual(b'target', link_or_sha1)
996
994
# We need to re-read the link because only now can we cache it
997
self.assertEqual([('read_link', 'a', ''),
998
('read_link', 'a', ''),
999
('read_link', 'a', ''),
1001
self.assertEqual([('l', 'target', 6, False, packed_stat)],
995
self.assertEqual([('read_link', b'a', b'')], state._log)
996
self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1004
1000
# Another call won't re-read the link
1005
self.assertEqual([('read_link', 'a', ''),
1006
('read_link', 'a', ''),
1007
('read_link', 'a', ''),
1009
link_or_sha1 = self.update_entry(state, entry, abspath='a',
1001
self.assertEqual([], state._log)
1002
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
1010
1003
stat_value=stat_value)
1011
self.assertEqual('target', link_or_sha1)
1012
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1004
self.assertEqual(b'target', link_or_sha1)
1005
self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1015
1008
def do_update_entry(self, state, entry, abspath):
1299
1309
basis_tree = tree.basis_tree()
1300
1310
def is_inside_raises(*args, **kwargs):
1301
1311
raise RuntimeError('stop this')
1302
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1312
self.overrideAttr(dirstate, 'is_inside', is_inside_raises)
1314
from breezy.bzr import _dirstate_helpers_pyx
1318
self.overrideAttr(_dirstate_helpers_pyx, 'is_inside', is_inside_raises)
1303
1319
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1305
1321
def test_simple_changes(self):
1306
1322
tree = self.make_branch_and_tree('tree')
1307
1323
self.build_tree(['tree/file'])
1308
tree.add(['file'], ['file-id'])
1309
self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
1324
tree.add(['file'], [b'file-id'])
1325
self.assertChangedFileIds([tree.get_root_id(), b'file-id'], tree)
1310
1326
tree.commit('one')
1311
1327
self.assertChangedFileIds([], tree)
1313
1329
def test_sha1provider_stat_and_sha1_used(self):
1314
1330
tree = self.make_branch_and_tree('tree')
1315
1331
self.build_tree(['tree/file'])
1316
tree.add(['file'], ['file-id'])
1332
tree.add(['file'], [b'file-id'])
1317
1333
tree.commit('one')
1318
1334
tree.lock_write()
1319
1335
self.addCleanup(tree.unlock)
1320
1336
state = tree._current_dirstate()
1321
1337
state._sha1_provider = UppercaseSHA1Provider()
1322
self.assertChangedFileIds(['file-id'], tree)
1338
self.assertChangedFileIds([b'file-id'], tree)
1341
class TestPackStat(tests.TestCase):
1342
"""Check packed representaton of stat values is robust on all inputs"""
1344
scenarios = helper_scenarios
1346
def pack(self, statlike_tuple):
1347
return self.helpers.pack_stat(os.stat_result(statlike_tuple))
1350
def unpack_field(packed_string, stat_field):
1351
return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
1353
def test_result(self):
1354
self.assertEqual(b"AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
1355
self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
1357
def test_giant_inode(self):
1358
packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
1359
self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
1361
def test_giant_size(self):
1362
packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
1363
self.assertEqual(4096, self.unpack_field(packed, "st_size"))
1365
def test_fractional_mtime(self):
1366
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
1367
self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
1369
def test_ancient_mtime(self):
1370
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
1371
self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
1373
def test_distant_mtime(self):
1374
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
1375
self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
1377
def test_fractional_ctime(self):
1378
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
1379
self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
1381
def test_ancient_ctime(self):
1382
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
1383
self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
1385
def test_distant_ctime(self):
1386
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
1387
self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
1389
def test_negative_dev(self):
1390
packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
1391
self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))