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):
136
120
bisect_split_idx, bisect_path_idx, path)
139
self.assertEqual(path, paths[bisect_path_idx+offset])
123
self.assertEqual(path, paths[bisect_path_idx + offset])
141
125
def split_for_dirblocks(self, paths):
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:
360
344
self.assertBisect(dirblocks, split_dirblocks, path)
362
346
def test_involved_cached(self):
363
347
"""This is where bisect_left diverges slightly."""
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',
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',
373
357
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
374
358
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',
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')
463
448
def test_simple_paths(self):
464
449
"""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')
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')
487
472
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')
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')
494
479
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')
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')
500
485
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"""
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"""
511
496
_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
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
522
507
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
509
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
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
533
def assertCmpPathByDirblock(self, paths):
518
def assertLtPathByDirblock(self, paths):
534
519
"""Compare all paths and make sure they evaluate to the correct order.
536
521
This does N^2 comparisons. It is assumed that ``paths`` is properly
541
526
# First, make sure the paths being passed in are correct
543
528
dirname, basename = os.path.split(p)
544
return dirname.split('/'), basename
529
return dirname.split(b'/'), basename
545
530
self.assertEqual(sorted(paths, key=_key), paths)
547
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
532
lt_path_by_dirblock = self.get_lt_path_by_dirblock()
548
533
for idx1, path1 in enumerate(paths):
549
534
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))
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))
567
541
def test_cmp_simple_paths(self):
568
542
"""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'])
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'])
572
547
def test_tricky_paths(self):
573
self.assertCmpPathByDirblock([
548
self.assertLtPathByDirblock([
575
'', 'a', 'a-a', 'a=a', 'b',
550
b'', b'a', b'a-a', b'a=a', b'b',
576
551
# Contents of 'a'
577
'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',
578
553
# Contents of 'a/a'
579
'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',
580
555
# Contents of 'a/a/a'
581
'a/a/a/a', 'a/a/a/b',
556
b'a/a/a/a', b'a/a/a/b',
582
557
# Contents of 'a/a/a-a',
583
'a/a/a-a/a', 'a/a/a-a/b',
558
b'a/a/a-a/a', b'a/a/a-a/b',
584
559
# Contents of 'a/a/a=a',
585
'a/a/a=a/a', 'a/a/a=a/b',
560
b'a/a/a=a/a', b'a/a/a=a/b',
586
561
# Contents of 'a/a-a'
588
563
# Contents of 'a/a-a/a'
589
'a/a-a/a/a', 'a/a-a/a/b',
564
b'a/a-a/a/a', b'a/a-a/a/b',
590
565
# Contents of 'a/a=a'
592
567
# Contents of 'a/b'
594
569
# Contents of 'a-a',
596
571
# Contents of 'a=a',
598
573
# Contents of 'b',
601
self.assertCmpPathByDirblock([
603
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
576
self.assertLtPathByDirblock([
578
b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
604
579
# content of 'a/'
605
'a/a', 'a/a-a', 'a/a-z',
607
'a/z', 'a/z-a', 'a/z-z',
580
b'a/a', b'a/a-a', b'a/a-z',
582
b'a/z', b'a/z-a', b'a/z-z',
609
584
# content of 'a/a/'
611
586
# content of 'a/a-a'
613
588
# content of 'a/a-z'
615
590
# content of 'a/a=a'
617
592
# content of 'a/a=z'
619
594
# content of 'a/z/'
621
596
# content of 'a-a'
623
598
# content of 'a-z'
625
600
# content of 'a=a'
627
602
# content of 'a=z'
631
606
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')
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')
640
615
def test_nonascii(self):
641
self.assertCmpPathByDirblock([
616
self.assertLtPathByDirblock([
643
'', 'a', '\xc2\xb5', '\xc3\xa5',
618
b'', b'a', b'\xc2\xb5', b'\xc3\xa5',
645
'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
620
b'a/a', b'a/\xc2\xb5', b'a/\xc3\xa5',
646
621
# content of 'a/a'
647
'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',
648
623
# content of 'a/\xc2\xb5'
649
'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',
650
625
# content of 'a/\xc3\xa5'
651
'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',
652
627
# content of '\xc2\xb5'
653
'\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',
654
629
# content of '\xc2\xe5'
655
'\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',
659
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
660
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
634
class TestCompiledLtPathByDirblock(TestLtPathByDirblock):
635
"""Test the pyrex implementation of _lt_path_by_dirblock"""
662
637
_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
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
669
644
class TestMemRChr(tests.TestCase):
672
647
_test_needs_features = [compiled_dirstate_helpers_feature]
674
649
def assertMemRChr(self, expected, s, c):
675
from bzrlib._dirstate_helpers_pyx import _py_memrchr
650
from breezy.bzr._dirstate_helpers_pyx import _py_memrchr
676
651
self.assertEqual(expected, _py_memrchr(s, c))
678
653
def test_missing(self):
679
self.assertMemRChr(None, '', 'a')
680
self.assertMemRChr(None, '', 'c')
681
self.assertMemRChr(None, 'abcdefghijklm', 'q')
682
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')
684
659
def test_single_entry(self):
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')
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')
692
667
def test_multiple(self):
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')
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')
701
676
def test_with_nulls(self):
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')
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')
712
687
class TestReadDirblocks(test_dirstate.TestCaseWithDirState):
775
752
def test_bisect_dirblock(self):
776
753
if compiled_dirstate_helpers_feature.available():
777
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
754
from breezy.bzr._dirstate_helpers_pyx import bisect_dirblock
779
from bzrlib._dirstate_helpers_py import bisect_dirblock
756
from breezy.bzr._dirstate_helpers_py import bisect_dirblock
780
757
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
782
759
def test__bisect_path_left(self):
783
760
if compiled_dirstate_helpers_feature.available():
784
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
761
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_left
786
from bzrlib._dirstate_helpers_py import _bisect_path_left
763
from breezy.bzr._dirstate_helpers_py import _bisect_path_left
787
764
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
789
766
def test__bisect_path_right(self):
790
767
if compiled_dirstate_helpers_feature.available():
791
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
768
from breezy.bzr._dirstate_helpers_pyx import _bisect_path_right
793
from bzrlib._dirstate_helpers_py import _bisect_path_right
770
from breezy.bzr._dirstate_helpers_py import _bisect_path_right
794
771
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
796
def test_cmp_by_dirs(self):
773
def test_lt_by_dirs(self):
797
774
if compiled_dirstate_helpers_feature.available():
798
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
775
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)
777
from ..bzr._dirstate_helpers_py import lt_by_dirs
778
self.assertIs(lt_by_dirs, dirstate.lt_by_dirs)
803
780
def test__read_dirblocks(self):
804
781
if compiled_dirstate_helpers_feature.available():
805
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
782
from breezy.bzr._dirstate_helpers_pyx import _read_dirblocks
807
from bzrlib._dirstate_helpers_py import _read_dirblocks
784
from breezy.bzr._dirstate_helpers_py import _read_dirblocks
808
785
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
810
787
def test_update_entry(self):
811
788
if compiled_dirstate_helpers_feature.available():
812
from bzrlib._dirstate_helpers_pyx import update_entry
789
from breezy.bzr._dirstate_helpers_pyx import update_entry
814
from bzrlib.dirstate import update_entry
791
from breezy.bzr.dirstate import update_entry
815
792
self.assertIs(update_entry, dirstate.update_entry)
817
794
def test_process_entry(self):
818
795
if compiled_dirstate_helpers_feature.available():
819
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
796
from breezy.bzr._dirstate_helpers_pyx import ProcessEntryC
820
797
self.assertIs(ProcessEntryC, dirstate._process_entry)
822
from bzrlib.dirstate import ProcessEntryPython
799
from breezy.bzr.dirstate import ProcessEntryPython
823
800
self.assertIs(ProcessEntryPython, dirstate._process_entry)
826
803
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
827
804
"""Test the DirState.update_entry functions"""
806
scenarios = multiply_scenarios(
807
dir_reader_scenarios(), ue_scenarios)
829
809
# Set by load_tests
830
810
update_entry = None
937
929
state.set_parent_trees(
938
930
[(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
940
entry = state._get_entry(0, path_utf8='a')
932
entry = state._get_entry(0, path_utf8=b'a')
942
link_or_sha1 = self.update_entry(state, entry, abspath='a',
943
stat_value=stat_value)
944
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',
946
self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
948
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
938
self.assertEqual([('is_exec', mode, False), ('sha1', b'a')],
940
self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
951
943
# Subsequent calls will just return the cached value
952
944
del state._log[:]
953
link_or_sha1 = self.update_entry(state, entry, abspath='a',
954
stat_value=stat_value)
955
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',
957
949
self.assertEqual([], state._log)
958
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
950
self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
961
953
def test_update_entry_symlink(self):
962
954
"""Update entry should read symlinks."""
963
self.requireFeature(tests.SymlinkFeature)
955
self.requireFeature(features.SymlinkFeature)
964
956
state, entry = self.get_state_with_a()
966
958
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
967
959
state._dirblock_state)
968
960
os.symlink('target', 'a')
970
state.adjust_time(-10) # Make the symlink look new
962
state.adjust_time(-10) # Make the symlink look new
971
963
stat_value = os.lstat('a')
972
964
packed_stat = dirstate.pack_stat(stat_value)
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)
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)
977
969
# Dirblock is not updated (the link is too new)
978
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
970
self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
980
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
972
# The file entry turned into a symlink, that is considered
973
# HASH modified worthy.
974
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
981
975
state._dirblock_state)
983
977
# Because the stat_value looks new, we should re-read the target
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)],
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)],
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)
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)
996
996
# 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)],
997
self.assertEqual([('read_link', b'a', b'')], state._log)
998
self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1004
1002
# 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',
1010
stat_value=stat_value)
1011
self.assertEqual('target', link_or_sha1)
1012
self.assertEqual([('l', 'target', 6, False, packed_stat)],
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)],
1015
1010
def do_update_entry(self, state, entry, abspath):
1297
1308
tree.lock_read()
1298
1309
self.addCleanup(tree.unlock)
1299
1310
basis_tree = tree.basis_tree()
1300
1312
def is_inside_raises(*args, **kwargs):
1301
1313
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)
1302
1322
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1303
1323
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1305
1325
def test_simple_changes(self):
1306
1326
tree = self.make_branch_and_tree('tree')
1307
1327
self.build_tree(['tree/file'])
1308
tree.add(['file'], ['file-id'])
1309
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)
1310
1330
tree.commit('one')
1311
1331
self.assertChangedFileIds([], tree)
1313
1333
def test_sha1provider_stat_and_sha1_used(self):
1314
1334
tree = self.make_branch_and_tree('tree')
1315
1335
self.build_tree(['tree/file'])
1316
tree.add(['file'], ['file-id'])
1336
tree.add(['file'], [b'file-id'])
1317
1337
tree.commit('one')
1318
1338
tree.lock_write()
1319
1339
self.addCleanup(tree.unlock)
1320
1340
state = tree._current_dirstate()
1321
1341
state._sha1_provider = UppercaseSHA1Provider()
1322
self.assertChangedFileIds(['file-id'], tree)
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"))