29
29
from bzrlib.tests import (
32
from bzrlib.tests.test_osutils import dir_reader_scenarios
33
from bzrlib.tests.scenarios import (
34
load_tests_apply_scenarios,
37
from bzrlib.tests import (
42
load_tests = load_tests_apply_scenarios
45
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
46
'bzrlib._dirstate_helpers_pyx')
49
# FIXME: we should also parametrize against SHA1Provider !
51
ue_scenarios = [('dirstate_Python',
52
{'update_entry': dirstate.py_update_entry})]
53
if compiled_dirstate_helpers_feature.available():
54
update_entry = compiled_dirstate_helpers_feature.module.update_entry
55
ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
57
pe_scenarios = [('dirstate_Python',
58
{'_process_entry': dirstate.ProcessEntryPython})]
59
if compiled_dirstate_helpers_feature.available():
60
process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
61
pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
35
from bzrlib import _dirstate_helpers_c
36
has_dirstate_helpers_c = True
38
has_dirstate_helpers_c = False
41
class _CompiledDirstateHelpersFeature(tests.Feature):
43
return has_dirstate_helpers_c
45
def feature_name(self):
46
return 'bzrlib._dirstate_helpers_c'
47
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
50
def load_tests(basic_tests, module, loader):
51
# FIXME: we should also parametrize against SHA1Provider !
52
suite = loader.suiteClass()
53
remaining_tests = basic_tests
55
dir_reader_scenarios = test_osutils.dir_reader_scenarios()
57
ue_scenarios = [('dirstate_Python',
58
{'update_entry': dirstate.py_update_entry})]
59
if has_dirstate_helpers_c:
60
c_scenario = ('dirstate_C',
61
{'update_entry': _dirstate_helpers_c.update_entry})
62
ue_scenarios.append(c_scenario)
63
process_entry_tests, remaining_tests = tests.split_suite_by_condition(
64
remaining_tests, tests.condition_isinstance(TestUpdateEntry))
65
tests.multiply_tests(process_entry_tests,
66
tests.multiply_scenarios(dir_reader_scenarios,
70
pe_scenarios = [('dirstate_Python',
71
{'_process_entry': dirstate.ProcessEntryPython})]
72
if has_dirstate_helpers_c:
73
c_scenario = ('dirstate_C',
74
{'_process_entry': _dirstate_helpers_c.ProcessEntryC})
75
pe_scenarios.append(c_scenario)
76
process_entry_tests, remaining_tests = tests.split_suite_by_condition(
77
remaining_tests, tests.condition_isinstance(TestProcessEntry))
78
tests.multiply_tests(process_entry_tests,
79
tests.multiply_scenarios(dir_reader_scenarios,
83
dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
84
remaining_tests, tests.condition_isinstance(
85
test_dirstate.TestCaseWithDirState))
86
tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
87
suite.addTest(remaining_tests)
64
92
class TestBisectPathMixin(object):
219
247
class TestBisectPathLeft(tests.TestCase, TestBisectPathMixin):
220
"""Run all Bisect Path tests against _bisect_path_left."""
248
"""Run all Bisect Path tests against _bisect_path_left_py."""
222
250
def get_bisect_path(self):
223
from bzrlib._dirstate_helpers_py import _bisect_path_left
224
return _bisect_path_left
251
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
252
return _bisect_path_left_py
226
254
def get_bisect(self):
227
255
return bisect.bisect_left, 0
230
258
class TestCompiledBisectPathLeft(TestBisectPathLeft):
231
"""Run all Bisect Path tests against _bisect_path_lect"""
259
"""Run all Bisect Path tests against _bisect_path_right_c"""
233
_test_needs_features = [compiled_dirstate_helpers_feature]
261
_test_needs_features = [CompiledDirstateHelpersFeature]
235
263
def get_bisect_path(self):
236
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
237
return _bisect_path_left
264
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
265
return _bisect_path_left_c
240
268
class TestBisectPathRight(tests.TestCase, TestBisectPathMixin):
241
"""Run all Bisect Path tests against _bisect_path_right"""
269
"""Run all Bisect Path tests against _bisect_path_right_py"""
243
271
def get_bisect_path(self):
244
from bzrlib._dirstate_helpers_py import _bisect_path_right
245
return _bisect_path_right
272
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
273
return _bisect_path_right_py
247
275
def get_bisect(self):
248
276
return bisect.bisect_right, -1
251
279
class TestCompiledBisectPathRight(TestBisectPathRight):
252
"""Run all Bisect Path tests against _bisect_path_right"""
280
"""Run all Bisect Path tests against _bisect_path_right_c"""
254
_test_needs_features = [compiled_dirstate_helpers_feature]
282
_test_needs_features = [CompiledDirstateHelpersFeature]
256
284
def get_bisect_path(self):
257
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
258
return _bisect_path_right
285
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
286
return _bisect_path_right_c
261
289
class TestBisectDirblock(tests.TestCase):
636
664
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
637
665
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
639
_test_needs_features = [compiled_dirstate_helpers_feature]
667
_test_needs_features = [CompiledDirstateHelpersFeature]
641
669
def get_cmp_by_dirs(self):
642
from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
643
return _cmp_path_by_dirblock
670
from bzrlib._dirstate_helpers_c import _cmp_path_by_dirblock_c
671
return _cmp_path_by_dirblock_c
646
674
class TestMemRChr(tests.TestCase):
647
675
"""Test memrchr functionality"""
649
_test_needs_features = [compiled_dirstate_helpers_feature]
677
_test_needs_features = [CompiledDirstateHelpersFeature]
651
679
def assertMemRChr(self, expected, s, c):
652
from bzrlib._dirstate_helpers_pyx import _py_memrchr
680
from bzrlib._dirstate_helpers_c import _py_memrchr
653
681
self.assertEqual(expected, _py_memrchr(s, c))
655
683
def test_missing(self):
736
758
class TestCompiledReadDirblocks(TestReadDirblocks):
737
759
"""Test the pyrex implementation of _read_dirblocks"""
739
_test_needs_features = [compiled_dirstate_helpers_feature]
761
_test_needs_features = [CompiledDirstateHelpersFeature]
741
763
def get_read_dirblocks(self):
742
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
743
return _read_dirblocks
764
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
765
return _read_dirblocks_c
746
768
class TestUsingCompiledIfAvailable(tests.TestCase):
747
769
"""Check that any compiled functions that are available are the default.
749
771
It is possible to have typos, etc in the import line, such that
750
_dirstate_helpers_pyx is actually available, but the compiled functions are
772
_dirstate_helpers_c is actually available, but the compiled functions are
754
776
def test_bisect_dirblock(self):
755
if compiled_dirstate_helpers_feature.available():
756
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
777
if CompiledDirstateHelpersFeature.available():
778
from bzrlib._dirstate_helpers_c import bisect_dirblock_c
779
self.assertIs(bisect_dirblock_c, dirstate.bisect_dirblock)
758
from bzrlib._dirstate_helpers_py import bisect_dirblock
759
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
781
from bzrlib._dirstate_helpers_py import bisect_dirblock_py
782
self.assertIs(bisect_dirblock_py, dirstate.bisect_dirblock)
761
784
def test__bisect_path_left(self):
762
if compiled_dirstate_helpers_feature.available():
763
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
785
if CompiledDirstateHelpersFeature.available():
786
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
787
self.assertIs(_bisect_path_left_c, dirstate._bisect_path_left)
765
from bzrlib._dirstate_helpers_py import _bisect_path_left
766
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
789
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
790
self.assertIs(_bisect_path_left_py, dirstate._bisect_path_left)
768
792
def test__bisect_path_right(self):
769
if compiled_dirstate_helpers_feature.available():
770
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
793
if CompiledDirstateHelpersFeature.available():
794
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
795
self.assertIs(_bisect_path_right_c, dirstate._bisect_path_right)
772
from bzrlib._dirstate_helpers_py import _bisect_path_right
773
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
797
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
798
self.assertIs(_bisect_path_right_py, dirstate._bisect_path_right)
775
800
def test_cmp_by_dirs(self):
776
if compiled_dirstate_helpers_feature.available():
777
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
801
if CompiledDirstateHelpersFeature.available():
802
from bzrlib._dirstate_helpers_c import cmp_by_dirs_c
803
self.assertIs(cmp_by_dirs_c, dirstate.cmp_by_dirs)
779
from bzrlib._dirstate_helpers_py import cmp_by_dirs
780
self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
805
from bzrlib._dirstate_helpers_py import cmp_by_dirs_py
806
self.assertIs(cmp_by_dirs_py, dirstate.cmp_by_dirs)
782
808
def test__read_dirblocks(self):
783
if compiled_dirstate_helpers_feature.available():
784
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
809
if CompiledDirstateHelpersFeature.available():
810
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
811
self.assertIs(_read_dirblocks_c, dirstate._read_dirblocks)
786
from bzrlib._dirstate_helpers_py import _read_dirblocks
787
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
813
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
814
self.assertIs(_read_dirblocks_py, dirstate._read_dirblocks)
789
816
def test_update_entry(self):
790
if compiled_dirstate_helpers_feature.available():
791
from bzrlib._dirstate_helpers_pyx import update_entry
817
if CompiledDirstateHelpersFeature.available():
818
from bzrlib._dirstate_helpers_c import update_entry
819
self.assertIs(update_entry, dirstate.update_entry)
793
from bzrlib.dirstate import update_entry
794
self.assertIs(update_entry, dirstate.update_entry)
821
from bzrlib.dirstate import py_update_entry
822
self.assertIs(py_update_entry, dirstate.py_update_entry)
796
824
def test_process_entry(self):
797
if compiled_dirstate_helpers_feature.available():
798
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
825
if CompiledDirstateHelpersFeature.available():
826
from bzrlib._dirstate_helpers_c import ProcessEntryC
799
827
self.assertIs(ProcessEntryC, dirstate._process_entry)
801
829
from bzrlib.dirstate import ProcessEntryPython
826
855
def test_observed_sha1_cachable(self):
827
856
state, entry = self.get_state_with_a()
829
857
atime = time.time() - 10
830
858
self.build_tree(['a'])
831
statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
832
statvalue.st_mtime = statvalue.st_ctime = atime
833
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
834
state._dirblock_state)
859
statvalue = os.lstat('a')
860
statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
861
statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
835
862
state._observed_sha1(entry, "foo", statvalue)
836
863
self.assertEqual('foo', entry[1][0][1])
837
864
packed_stat = dirstate.pack_stat(statvalue)
838
865
self.assertEqual(packed_stat, entry[1][0][4])
839
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
840
state._dirblock_state)
842
867
def test_observed_sha1_not_cachable(self):
843
868
state, entry = self.get_state_with_a()
845
869
oldval = entry[1][0][1]
846
870
oldstat = entry[1][0][4]
847
871
self.build_tree(['a'])
848
872
statvalue = os.lstat('a')
849
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
850
state._dirblock_state)
851
873
state._observed_sha1(entry, "foo", statvalue)
852
874
self.assertEqual(oldval, entry[1][0][1])
853
875
self.assertEqual(oldstat, entry[1][0][4])
854
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
855
state._dirblock_state)
857
877
def test_update_entry(self):
858
878
state, _ = self.get_state_with_a()
883
903
stat_value=stat_value)
884
904
self.assertEqual(None, link_or_sha1)
886
# The dirblock entry should not have computed or cached the file's
887
# sha1, but it did update the files' st_size. However, this is not
888
# worth writing a dirstate file for, so we leave the state UNMODIFIED
906
# The dirblock entry should not have cached the file's sha1 (too new)
889
907
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
891
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
909
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
892
910
state._dirblock_state)
893
911
mode = stat_value.st_mode
894
912
self.assertEqual([('is_exec', mode, False)], state._log)
971
988
# Dirblock is not updated (the link is too new)
972
989
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
974
# The file entry turned into a symlink, that is considered
975
# HASH modified worthy.
976
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
991
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
977
992
state._dirblock_state)
979
994
# Because the stat_value looks new, we should re-read the target
981
995
link_or_sha1 = self.update_entry(state, entry, abspath='a',
982
996
stat_value=stat_value)
983
997
self.assertEqual('target', link_or_sha1)
984
self.assertEqual([('read_link', 'a', '')], state._log)
998
self.assertEqual([('read_link', 'a', ''),
999
('read_link', 'a', ''),
985
1001
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
988
1003
state.adjust_time(+20) # Skip into the future, all files look old
990
1004
link_or_sha1 = self.update_entry(state, entry, abspath='a',
991
1005
stat_value=stat_value)
992
# The symlink stayed a symlink. So while it is new enough to cache, we
993
# don't bother setting the flag, because it is not really worth saving
994
# (when we stat the symlink, we'll have paged in the target.)
995
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
996
state._dirblock_state)
997
1006
self.assertEqual('target', link_or_sha1)
998
1007
# We need to re-read the link because only now can we cache it
999
self.assertEqual([('read_link', 'a', '')], state._log)
1008
self.assertEqual([('read_link', 'a', ''),
1009
('read_link', 'a', ''),
1010
('read_link', 'a', ''),
1000
1012
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1004
1015
# Another call won't re-read the link
1005
self.assertEqual([], state._log)
1016
self.assertEqual([('read_link', 'a', ''),
1017
('read_link', 'a', ''),
1018
('read_link', 'a', ''),
1006
1020
link_or_sha1 = self.update_entry(state, entry, abspath='a',
1007
1021
stat_value=stat_value)
1008
1022
self.assertEqual('target', link_or_sha1)
1023
1037
self.build_tree(['a/'])
1024
1038
state.adjust_time(+20)
1025
1039
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1026
# a/ used to be a file, but is now a directory, worth saving
1027
1040
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1028
1041
state._dirblock_state)
1030
1043
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1031
1044
state._dirblock_state)
1032
# No changes to a/ means not worth saving.
1033
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1034
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1035
state._dirblock_state)
1036
# Change the last-modified time for the directory
1037
t = time.time() - 100.0
1039
os.utime('a', (t, t))
1041
# It looks like Win32 + FAT doesn't allow to change times on a dir.
1042
raise tests.TestSkipped("can't update mtime of a dir on FAT")
1043
saved_packed_stat = entry[1][0][-1]
1044
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1045
# We *do* go ahead and update the information in the dirblocks, but we
1046
# don't bother setting IN_MEMORY_MODIFIED because it is trivial to
1048
self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1045
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1049
1046
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1050
1047
state._dirblock_state)
1302
1301
self.assertEqual(sorted(expected), sorted(file_ids))
1304
def test_exceptions_raised(self):
1305
# This is a direct test of bug #495023, it relies on osutils.is_inside
1306
# getting called in an inner function. Which makes it a bit brittle,
1307
# but at least it does reproduce the bug.
1308
tree = self.make_branch_and_tree('tree')
1309
self.build_tree(['tree/file', 'tree/dir/', 'tree/dir/sub',
1310
'tree/dir2/', 'tree/dir2/sub2'])
1311
tree.add(['file', 'dir', 'dir/sub', 'dir2', 'dir2/sub2'])
1312
tree.commit('first commit')
1314
self.addCleanup(tree.unlock)
1315
basis_tree = tree.basis_tree()
1316
def is_inside_raises(*args, **kwargs):
1317
raise RuntimeError('stop this')
1318
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1319
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1321
1303
def test_simple_changes(self):
1322
1304
tree = self.make_branch_and_tree('tree')
1323
1305
self.build_tree(['tree/file'])