29
from bzrlib.tests import (
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}))
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)
71
87
class TestBisectPathMixin(object):
120
136
bisect_split_idx, bisect_path_idx, path)
123
self.assertEqual(path, paths[bisect_path_idx + offset])
139
self.assertEqual(path, paths[bisect_path_idx+offset])
125
141
def split_for_dirblocks(self, paths):
126
142
dir_split_paths = []
127
143
for path in paths:
128
144
dirname, basename = os.path.split(path)
129
dir_split_paths.append((dirname.split(b'/'), basename))
145
dir_split_paths.append((dirname.split('/'), basename))
130
146
dir_split_paths.sort()
131
147
return dir_split_paths
133
149
def test_simple(self):
134
150
"""In the simple case it works just like bisect_left"""
135
paths = [b'', b'a', b'b', b'c', b'd']
151
paths = ['', 'a', 'b', 'c', 'd']
136
152
split_paths = self.split_for_dirblocks(paths)
137
153
for path in paths:
138
154
self.assertBisect(paths, split_paths, path, exists=True)
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)
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)
149
165
def test_involved(self):
150
166
"""This is where bisect_path_* diverges slightly."""
309
325
Also, ensure that the paths are in proper sorted order.
311
327
dirblocks = [(path, []) for path in paths]
312
split_dirblocks = [(path.split(b'/'), []) for path in paths]
328
split_dirblocks = [(path.split('/'), []) for path in paths]
313
329
self.assertEqual(sorted(split_dirblocks), split_dirblocks)
314
330
return dirblocks, split_dirblocks
316
332
def test_simple(self):
317
333
"""In the simple case it works just like bisect_left"""
318
paths = [b'', b'a', b'b', b'c', b'd']
334
paths = ['', 'a', 'b', 'c', 'd']
319
335
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
320
336
for path in paths:
321
337
self.assertBisect(dirblocks, split_dirblocks, path)
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')
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')
332
348
def test_involved(self):
333
349
"""This is where bisect_left diverges slightly."""
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',
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',
342
358
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
343
359
for path in paths:
344
360
self.assertBisect(dirblocks, split_dirblocks, path)
346
362
def test_involved_cached(self):
347
363
"""This is where bisect_left diverges slightly."""
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',
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',
365
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
366
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
368
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
369
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
357
373
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
358
374
for path in paths:
400
416
:param str1: string to compare
401
417
:param str2: string to compare
403
lt_by_dirs = self.get_lt_by_dirs()
419
cmp_by_dirs = self.get_cmp_by_dirs()
404
420
if expected == 0:
405
421
self.assertEqual(str1, str2)
406
self.assertFalse(lt_by_dirs(str1, str2))
407
self.assertFalse(lt_by_dirs(str2, str1))
422
self.assertEqual(0, cmp_by_dirs(str1, str2))
423
self.assertEqual(0, cmp_by_dirs(str2, str1))
408
424
elif expected > 0:
409
self.assertFalse(lt_by_dirs(str1, str2))
410
self.assertTrue(lt_by_dirs(str2, str1))
425
self.assertPositive(cmp_by_dirs(str1, str2))
426
self.assertNegative(cmp_by_dirs(str2, str1))
412
self.assertTrue(lt_by_dirs(str1, str2))
413
self.assertFalse(lt_by_dirs(str2, str1))
428
self.assertNegative(cmp_by_dirs(str1, str2))
429
self.assertPositive(cmp_by_dirs(str2, str1))
415
431
def test_cmp_empty(self):
416
432
"""Compare against the empty string."""
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'')
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/', '')
429
445
def test_cmp_same_str(self):
430
446
"""Compare the same string"""
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')
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')
448
463
def test_simple_paths(self):
449
464
"""Compare strings that act like normal string comparison"""
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')
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')
472
487
def test_tricky_paths(self):
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')
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')
479
494
def test_cmp_unicode_not_allowed(self):
480
lt_by_dirs = self.get_lt_by_dirs()
481
self.assertRaises(TypeError, lt_by_dirs, u'Unicode', b'str')
482
self.assertRaises(TypeError, lt_by_dirs, b'str', u'Unicode')
483
self.assertRaises(TypeError, lt_by_dirs, u'Unicode', u'Unicode')
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')
485
500
def test_cmp_non_ascii(self):
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'
493
class TestCompiledLtByDirs(TestLtByDirs):
494
"""Test the pyrex implementation of lt_by_dirs"""
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"""
496
511
_test_needs_features = [compiled_dirstate_helpers_feature]
498
def get_lt_by_dirs(self):
499
from ..bzr._dirstate_helpers_pyx import lt_by_dirs
503
class TestLtPathByDirblock(tests.TestCase):
504
"""Test an implementation of _lt_path_by_dirblock()
506
_lt_path_by_dirblock() compares two paths using the sort order used by
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
507
522
DirState. All paths in the same directory are sorted together.
509
Child test cases can override ``get_lt_path_by_dirblock`` to test a specific
524
Child test cases can override ``get_cmp_path_by_dirblock`` to test a specific
513
def get_lt_path_by_dirblock(self):
514
"""Get a specific implementation of _lt_path_by_dirblock."""
515
from ..bzr._dirstate_helpers_py import _lt_path_by_dirblock
516
return _lt_path_by_dirblock
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
518
def assertLtPathByDirblock(self, paths):
533
def assertCmpPathByDirblock(self, paths):
519
534
"""Compare all paths and make sure they evaluate to the correct order.
521
536
This does N^2 comparisons. It is assumed that ``paths`` is properly
526
541
# First, make sure the paths being passed in are correct
528
543
dirname, basename = os.path.split(p)
529
return dirname.split(b'/'), basename
544
return dirname.split('/'), basename
530
545
self.assertEqual(sorted(paths, key=_key), paths)
532
lt_path_by_dirblock = self.get_lt_path_by_dirblock()
547
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
533
548
for idx1, path1 in enumerate(paths):
534
549
for idx2, path2 in enumerate(paths):
535
lt_result = lt_path_by_dirblock(path1, path2)
536
self.assertEqual(idx1 < idx2, lt_result,
537
'%s did not state that %r < %r, lt=%s'
538
% (lt_path_by_dirblock.__name__,
539
path1, path2, lt_result))
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))
541
567
def test_cmp_simple_paths(self):
542
568
"""Compare against the empty string."""
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'])
569
self.assertCmpPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
570
self.assertCmpPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
547
572
def test_tricky_paths(self):
548
self.assertLtPathByDirblock([
573
self.assertCmpPathByDirblock([
550
b'', b'a', b'a-a', b'a=a', b'b',
575
'', 'a', 'a-a', 'a=a', 'b',
551
576
# Contents of 'a'
552
b'a/a', b'a/a-a', b'a/a=a', b'a/b',
577
'a/a', 'a/a-a', 'a/a=a', 'a/b',
553
578
# Contents of 'a/a'
554
b'a/a/a', b'a/a/a-a', b'a/a/a=a',
579
'a/a/a', 'a/a/a-a', 'a/a/a=a',
555
580
# Contents of 'a/a/a'
556
b'a/a/a/a', b'a/a/a/b',
581
'a/a/a/a', 'a/a/a/b',
557
582
# Contents of 'a/a/a-a',
558
b'a/a/a-a/a', b'a/a/a-a/b',
583
'a/a/a-a/a', 'a/a/a-a/b',
559
584
# Contents of 'a/a/a=a',
560
b'a/a/a=a/a', b'a/a/a=a/b',
585
'a/a/a=a/a', 'a/a/a=a/b',
561
586
# Contents of 'a/a-a'
563
588
# Contents of 'a/a-a/a'
564
b'a/a-a/a/a', b'a/a-a/a/b',
589
'a/a-a/a/a', 'a/a-a/a/b',
565
590
# Contents of 'a/a=a'
567
592
# Contents of 'a/b'
569
594
# Contents of 'a-a',
571
596
# Contents of 'a=a',
573
598
# Contents of 'b',
576
self.assertLtPathByDirblock([
578
b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
601
self.assertCmpPathByDirblock([
603
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
579
604
# content of 'a/'
580
b'a/a', b'a/a-a', b'a/a-z',
582
b'a/z', b'a/z-a', b'a/z-z',
605
'a/a', 'a/a-a', 'a/a-z',
607
'a/z', 'a/z-a', 'a/z-z',
584
609
# content of 'a/a/'
586
611
# content of 'a/a-a'
588
613
# content of 'a/a-z'
590
615
# content of 'a/a=a'
592
617
# content of 'a/a=z'
594
619
# content of 'a/z/'
596
621
# content of 'a-a'
598
623
# content of 'a-z'
600
625
# content of 'a=a'
602
627
# content of 'a=z'
606
631
def test_unicode_not_allowed(self):
607
lt_path_by_dirblock = self.get_lt_path_by_dirblock()
608
self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', 'str')
609
self.assertRaises(TypeError, lt_path_by_dirblock, 'str', u'Uni')
610
self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', u'Uni')
611
self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', 'x/str')
612
self.assertRaises(TypeError, lt_path_by_dirblock, 'x/str', u'x/Uni')
613
self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', u'x/Uni')
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')
615
640
def test_nonascii(self):
616
self.assertLtPathByDirblock([
641
self.assertCmpPathByDirblock([
618
b'', b'a', b'\xc2\xb5', b'\xc3\xa5',
643
'', 'a', '\xc2\xb5', '\xc3\xa5',
620
b'a/a', b'a/\xc2\xb5', b'a/\xc3\xa5',
645
'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
621
646
# content of 'a/a'
622
b'a/a/a', b'a/a/\xc2\xb5', b'a/a/\xc3\xa5',
647
'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
623
648
# content of 'a/\xc2\xb5'
624
b'a/\xc2\xb5/a', b'a/\xc2\xb5/\xc2\xb5', b'a/\xc2\xb5/\xc3\xa5',
649
'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
625
650
# content of 'a/\xc3\xa5'
626
b'a/\xc3\xa5/a', b'a/\xc3\xa5/\xc2\xb5', b'a/\xc3\xa5/\xc3\xa5',
651
'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
627
652
# content of '\xc2\xb5'
628
b'\xc2\xb5/a', b'\xc2\xb5/\xc2\xb5', b'\xc2\xb5/\xc3\xa5',
653
'\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
629
654
# content of '\xc2\xe5'
630
b'\xc3\xa5/a', b'\xc3\xa5/\xc2\xb5', b'\xc3\xa5/\xc3\xa5',
655
'\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
634
class TestCompiledLtPathByDirblock(TestLtPathByDirblock):
635
"""Test the pyrex implementation of _lt_path_by_dirblock"""
659
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
660
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
637
662
_test_needs_features = [compiled_dirstate_helpers_feature]
639
def get_lt_path_by_dirblock(self):
640
from ..bzr._dirstate_helpers_pyx import _lt_path_by_dirblock
641
return _lt_path_by_dirblock
664
def get_cmp_by_dirs(self):
665
from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
666
return _cmp_path_by_dirblock
644
669
class TestMemRChr(tests.TestCase):
647
672
_test_needs_features = [compiled_dirstate_helpers_feature]
649
674
def assertMemRChr(self, expected, s, c):
650
from breezy.bzr._dirstate_helpers_pyx import _py_memrchr
675
from bzrlib._dirstate_helpers_pyx import _py_memrchr
651
676
self.assertEqual(expected, _py_memrchr(s, c))
653
678
def test_missing(self):
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')
679
self.assertMemRChr(None, '', 'a')
680
self.assertMemRChr(None, '', 'c')
681
self.assertMemRChr(None, 'abcdefghijklm', 'q')
682
self.assertMemRChr(None, 'aaaaaaaaaaaaaaaaaaaaaaa', 'b')
659
684
def test_single_entry(self):
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')
685
self.assertMemRChr(0, 'abcdefghijklm', 'a')
686
self.assertMemRChr(1, 'abcdefghijklm', 'b')
687
self.assertMemRChr(2, 'abcdefghijklm', 'c')
688
self.assertMemRChr(10, 'abcdefghijklm', 'k')
689
self.assertMemRChr(11, 'abcdefghijklm', 'l')
690
self.assertMemRChr(12, 'abcdefghijklm', 'm')
667
692
def test_multiple(self):
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')
693
self.assertMemRChr(10, 'abcdefjklmabcdefghijklm', 'a')
694
self.assertMemRChr(11, 'abcdefjklmabcdefghijklm', 'b')
695
self.assertMemRChr(12, 'abcdefjklmabcdefghijklm', 'c')
696
self.assertMemRChr(20, 'abcdefjklmabcdefghijklm', 'k')
697
self.assertMemRChr(21, 'abcdefjklmabcdefghijklm', 'l')
698
self.assertMemRChr(22, 'abcdefjklmabcdefghijklm', 'm')
699
self.assertMemRChr(22, 'aaaaaaaaaaaaaaaaaaaaaaa', 'a')
676
701
def test_with_nulls(self):
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')
702
self.assertMemRChr(10, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'a')
703
self.assertMemRChr(11, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'b')
704
self.assertMemRChr(12, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'c')
705
self.assertMemRChr(20, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'k')
706
self.assertMemRChr(21, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'l')
707
self.assertMemRChr(22, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'm')
708
self.assertMemRChr(22, 'aaa\0\0\0aaaaaaa\0\0\0aaaaaaa', 'a')
709
self.assertMemRChr(9, '\0\0\0\0\0\0\0\0\0\0', '\0')
687
712
class TestReadDirblocks(test_dirstate.TestCaseWithDirState):
752
775
def test_bisect_dirblock(self):
753
776
if compiled_dirstate_helpers_feature.available():
754
from breezy.bzr._dirstate_helpers_pyx import bisect_dirblock
777
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
756
from breezy.bzr._dirstate_helpers_py import bisect_dirblock
779
from bzrlib._dirstate_helpers_py import bisect_dirblock
757
780
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
759
782
def test__bisect_path_left(self):
760
783
if compiled_dirstate_helpers_feature.available():
761
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_left
784
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
763
from breezy.bzr._dirstate_helpers_py import _bisect_path_left
786
from bzrlib._dirstate_helpers_py import _bisect_path_left
764
787
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
766
789
def test__bisect_path_right(self):
767
790
if compiled_dirstate_helpers_feature.available():
768
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_right
791
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
770
from breezy.bzr._dirstate_helpers_py import _bisect_path_right
793
from bzrlib._dirstate_helpers_py import _bisect_path_right
771
794
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
773
def test_lt_by_dirs(self):
796
def test_cmp_by_dirs(self):
774
797
if compiled_dirstate_helpers_feature.available():
775
from ..bzr._dirstate_helpers_pyx import lt_by_dirs
798
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
777
from ..bzr._dirstate_helpers_py import lt_by_dirs
778
self.assertIs(lt_by_dirs, dirstate.lt_by_dirs)
800
from bzrlib._dirstate_helpers_py import cmp_by_dirs
801
self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
780
803
def test__read_dirblocks(self):
781
804
if compiled_dirstate_helpers_feature.available():
782
from breezy.bzr._dirstate_helpers_pyx import _read_dirblocks
805
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
784
from breezy.bzr._dirstate_helpers_py import _read_dirblocks
807
from bzrlib._dirstate_helpers_py import _read_dirblocks
785
808
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
787
810
def test_update_entry(self):
788
811
if compiled_dirstate_helpers_feature.available():
789
from breezy.bzr._dirstate_helpers_pyx import update_entry
812
from bzrlib._dirstate_helpers_pyx import update_entry
791
from breezy.bzr.dirstate import update_entry
814
from bzrlib.dirstate import update_entry
792
815
self.assertIs(update_entry, dirstate.update_entry)
794
817
def test_process_entry(self):
795
818
if compiled_dirstate_helpers_feature.available():
796
from breezy.bzr._dirstate_helpers_pyx import ProcessEntryC
819
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
797
820
self.assertIs(ProcessEntryC, dirstate._process_entry)
799
from breezy.bzr.dirstate import ProcessEntryPython
822
from bzrlib.dirstate import ProcessEntryPython
800
823
self.assertIs(ProcessEntryPython, dirstate._process_entry)
803
826
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
804
827
"""Test the DirState.update_entry functions"""
806
scenarios = multiply_scenarios(
807
dir_reader_scenarios(), ue_scenarios)
809
829
# Set by load_tests
810
830
update_entry = None
929
937
state.set_parent_trees(
930
938
[(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
932
entry = state._get_entry(0, path_utf8=b'a')
940
entry = state._get_entry(0, path_utf8='a')
934
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
935
stat_value=stat_value)
936
self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
942
link_or_sha1 = self.update_entry(state, entry, abspath='a',
943
stat_value=stat_value)
944
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
938
self.assertEqual([('is_exec', mode, False), ('sha1', b'a')],
940
self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
946
self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
948
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
943
951
# Subsequent calls will just return the cached value
944
952
del state._log[:]
945
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
946
stat_value=stat_value)
947
self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
953
link_or_sha1 = self.update_entry(state, entry, abspath='a',
954
stat_value=stat_value)
955
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
949
957
self.assertEqual([], state._log)
950
self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
958
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
953
961
def test_update_entry_symlink(self):
954
962
"""Update entry should read symlinks."""
955
self.requireFeature(features.SymlinkFeature)
963
self.requireFeature(tests.SymlinkFeature)
956
964
state, entry = self.get_state_with_a()
958
966
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
959
967
state._dirblock_state)
960
968
os.symlink('target', 'a')
962
state.adjust_time(-10) # Make the symlink look new
970
state.adjust_time(-10) # Make the symlink look new
963
971
stat_value = os.lstat('a')
964
972
packed_stat = dirstate.pack_stat(stat_value)
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)
973
link_or_sha1 = self.update_entry(state, entry, abspath='a',
974
stat_value=stat_value)
975
self.assertEqual('target', link_or_sha1)
976
self.assertEqual([('read_link', 'a', '')], state._log)
969
977
# Dirblock is not updated (the link is too new)
970
self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
978
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
972
# The file entry turned into a symlink, that is considered
973
# HASH modified worthy.
974
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
980
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
975
981
state._dirblock_state)
977
983
# Because the stat_value looks new, we should re-read the target
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)],
984
link_or_sha1 = self.update_entry(state, entry, abspath='a',
985
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)],
986
state.adjust_time(+20) # Skip into the future, all files look old
988
link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
989
stat_value=stat_value)
990
# The symlink stayed a symlink. So while it is new enough to cache, we
991
# don't bother setting the flag, because it is not really worth saving
992
# (when we stat the symlink, we'll have paged in the target.)
993
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
994
state._dirblock_state)
995
self.assertEqual(b'target', link_or_sha1)
992
state.adjust_time(+20) # Skip into the future, all files look old
993
link_or_sha1 = self.update_entry(state, entry, abspath='a',
994
stat_value=stat_value)
995
self.assertEqual('target', link_or_sha1)
996
996
# We need to re-read the link because only now can we cache it
997
self.assertEqual([('read_link', b'a', b'')], state._log)
998
self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
997
self.assertEqual([('read_link', 'a', ''),
998
('read_link', 'a', ''),
999
('read_link', 'a', ''),
1001
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1002
1004
# Another call won't re-read the link
1003
self.assertEqual([], state._log)
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)],
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',
1010
stat_value=stat_value)
1011
self.assertEqual('target', link_or_sha1)
1012
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1010
1015
def do_update_entry(self, state, entry, abspath):
1308
1297
tree.lock_read()
1309
1298
self.addCleanup(tree.unlock)
1310
1299
basis_tree = tree.basis_tree()
1312
1300
def is_inside_raises(*args, **kwargs):
1313
1301
raise RuntimeError('stop this')
1314
self.overrideAttr(dirstate, 'is_inside', is_inside_raises)
1316
from breezy.bzr import _dirstate_helpers_pyx
1320
self.overrideAttr(_dirstate_helpers_pyx,
1321
'is_inside', is_inside_raises)
1322
1302
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1323
1303
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1325
1305
def test_simple_changes(self):
1326
1306
tree = self.make_branch_and_tree('tree')
1327
1307
self.build_tree(['tree/file'])
1328
tree.add(['file'], [b'file-id'])
1329
self.assertChangedFileIds([tree.path2id(''), b'file-id'], tree)
1308
tree.add(['file'], ['file-id'])
1309
self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
1330
1310
tree.commit('one')
1331
1311
self.assertChangedFileIds([], tree)
1333
1313
def test_sha1provider_stat_and_sha1_used(self):
1334
1314
tree = self.make_branch_and_tree('tree')
1335
1315
self.build_tree(['tree/file'])
1336
tree.add(['file'], [b'file-id'])
1316
tree.add(['file'], ['file-id'])
1337
1317
tree.commit('one')
1338
1318
tree.lock_write()
1339
1319
self.addCleanup(tree.unlock)
1340
1320
state = tree._current_dirstate()
1341
1321
state._sha1_provider = UppercaseSHA1Provider()
1342
self.assertChangedFileIds([b'file-id'], tree)
1345
class TestPackStat(tests.TestCase):
1346
"""Check packed representaton of stat values is robust on all inputs"""
1348
scenarios = helper_scenarios
1350
def pack(self, statlike_tuple):
1351
return self.helpers.pack_stat(os.stat_result(statlike_tuple))
1354
def unpack_field(packed_string, stat_field):
1355
return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
1357
def test_result(self):
1358
self.assertEqual(b"AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
1359
self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
1361
def test_giant_inode(self):
1362
packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
1363
self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
1365
def test_giant_size(self):
1366
packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
1367
self.assertEqual(4096, self.unpack_field(packed, "st_size"))
1369
def test_fractional_mtime(self):
1370
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
1371
self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
1373
def test_ancient_mtime(self):
1374
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
1375
self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
1377
def test_distant_mtime(self):
1378
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
1379
self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
1381
def test_fractional_ctime(self):
1382
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
1383
self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
1385
def test_ancient_ctime(self):
1386
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
1387
self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
1389
def test_distant_ctime(self):
1390
packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
1391
self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
1393
def test_negative_dev(self):
1394
packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
1395
self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))
1322
self.assertChangedFileIds(['file-id'], tree)