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,
39
load_tests = load_tests_apply_scenarios
42
compiled_dirstate_helpers_feature = tests.ModuleAvailableFeature(
43
'bzrlib._dirstate_helpers_pyx')
46
# FIXME: we should also parametrize against SHA1Provider !
48
ue_scenarios = [('dirstate_Python',
49
{'update_entry': dirstate.py_update_entry})]
50
if compiled_dirstate_helpers_feature.available():
51
update_entry = compiled_dirstate_helpers_feature.module.update_entry
52
ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
54
pe_scenarios = [('dirstate_Python',
55
{'_process_entry': dirstate.ProcessEntryPython})]
56
if compiled_dirstate_helpers_feature.available():
57
process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
58
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)
61
92
class TestBisectPathMixin(object):
216
247
class TestBisectPathLeft(tests.TestCase, TestBisectPathMixin):
217
"""Run all Bisect Path tests against _bisect_path_left."""
248
"""Run all Bisect Path tests against _bisect_path_left_py."""
219
250
def get_bisect_path(self):
220
from bzrlib._dirstate_helpers_py import _bisect_path_left
221
return _bisect_path_left
251
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
252
return _bisect_path_left_py
223
254
def get_bisect(self):
224
255
return bisect.bisect_left, 0
227
258
class TestCompiledBisectPathLeft(TestBisectPathLeft):
228
"""Run all Bisect Path tests against _bisect_path_lect"""
259
"""Run all Bisect Path tests against _bisect_path_right_c"""
230
_test_needs_features = [compiled_dirstate_helpers_feature]
261
_test_needs_features = [CompiledDirstateHelpersFeature]
232
263
def get_bisect_path(self):
233
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
234
return _bisect_path_left
264
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
265
return _bisect_path_left_c
237
268
class TestBisectPathRight(tests.TestCase, TestBisectPathMixin):
238
"""Run all Bisect Path tests against _bisect_path_right"""
269
"""Run all Bisect Path tests against _bisect_path_right_py"""
240
271
def get_bisect_path(self):
241
from bzrlib._dirstate_helpers_py import _bisect_path_right
242
return _bisect_path_right
272
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
273
return _bisect_path_right_py
244
275
def get_bisect(self):
245
276
return bisect.bisect_right, -1
248
279
class TestCompiledBisectPathRight(TestBisectPathRight):
249
"""Run all Bisect Path tests against _bisect_path_right"""
280
"""Run all Bisect Path tests against _bisect_path_right_c"""
251
_test_needs_features = [compiled_dirstate_helpers_feature]
282
_test_needs_features = [CompiledDirstateHelpersFeature]
253
284
def get_bisect_path(self):
254
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
255
return _bisect_path_right
285
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
286
return _bisect_path_right_c
258
289
class TestBisectDirblock(tests.TestCase):
633
664
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
634
665
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
636
_test_needs_features = [compiled_dirstate_helpers_feature]
667
_test_needs_features = [CompiledDirstateHelpersFeature]
638
669
def get_cmp_by_dirs(self):
639
from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
640
return _cmp_path_by_dirblock
670
from bzrlib._dirstate_helpers_c import _cmp_path_by_dirblock_c
671
return _cmp_path_by_dirblock_c
643
674
class TestMemRChr(tests.TestCase):
644
675
"""Test memrchr functionality"""
646
_test_needs_features = [compiled_dirstate_helpers_feature]
677
_test_needs_features = [CompiledDirstateHelpersFeature]
648
679
def assertMemRChr(self, expected, s, c):
649
from bzrlib._dirstate_helpers_pyx import _py_memrchr
680
from bzrlib._dirstate_helpers_c import _py_memrchr
650
681
self.assertEqual(expected, _py_memrchr(s, c))
652
683
def test_missing(self):
733
758
class TestCompiledReadDirblocks(TestReadDirblocks):
734
759
"""Test the pyrex implementation of _read_dirblocks"""
736
_test_needs_features = [compiled_dirstate_helpers_feature]
761
_test_needs_features = [CompiledDirstateHelpersFeature]
738
763
def get_read_dirblocks(self):
739
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
740
return _read_dirblocks
764
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
765
return _read_dirblocks_c
743
768
class TestUsingCompiledIfAvailable(tests.TestCase):
744
769
"""Check that any compiled functions that are available are the default.
746
771
It is possible to have typos, etc in the import line, such that
747
_dirstate_helpers_pyx is actually available, but the compiled functions are
772
_dirstate_helpers_c is actually available, but the compiled functions are
751
776
def test_bisect_dirblock(self):
752
if compiled_dirstate_helpers_feature.available():
753
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)
755
from bzrlib._dirstate_helpers_py import bisect_dirblock
756
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)
758
784
def test__bisect_path_left(self):
759
if compiled_dirstate_helpers_feature.available():
760
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)
762
from bzrlib._dirstate_helpers_py import _bisect_path_left
763
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)
765
792
def test__bisect_path_right(self):
766
if compiled_dirstate_helpers_feature.available():
767
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)
769
from bzrlib._dirstate_helpers_py import _bisect_path_right
770
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)
772
800
def test_cmp_by_dirs(self):
773
if compiled_dirstate_helpers_feature.available():
774
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)
776
from bzrlib._dirstate_helpers_py import cmp_by_dirs
777
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)
779
808
def test__read_dirblocks(self):
780
if compiled_dirstate_helpers_feature.available():
781
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)
783
from bzrlib._dirstate_helpers_py import _read_dirblocks
784
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)
786
816
def test_update_entry(self):
787
if compiled_dirstate_helpers_feature.available():
788
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)
790
from bzrlib.dirstate import update_entry
791
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)
793
824
def test_process_entry(self):
794
if compiled_dirstate_helpers_feature.available():
795
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
825
if CompiledDirstateHelpersFeature.available():
826
from bzrlib._dirstate_helpers_c import ProcessEntryC
796
827
self.assertIs(ProcessEntryC, dirstate._process_entry)
798
829
from bzrlib.dirstate import ProcessEntryPython
823
855
def test_observed_sha1_cachable(self):
824
856
state, entry = self.get_state_with_a()
826
857
atime = time.time() - 10
827
858
self.build_tree(['a'])
828
statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
829
statvalue.st_mtime = statvalue.st_ctime = atime
830
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
831
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)
832
862
state._observed_sha1(entry, "foo", statvalue)
833
863
self.assertEqual('foo', entry[1][0][1])
834
864
packed_stat = dirstate.pack_stat(statvalue)
835
865
self.assertEqual(packed_stat, entry[1][0][4])
836
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
837
state._dirblock_state)
839
867
def test_observed_sha1_not_cachable(self):
840
868
state, entry = self.get_state_with_a()
842
869
oldval = entry[1][0][1]
843
870
oldstat = entry[1][0][4]
844
871
self.build_tree(['a'])
845
872
statvalue = os.lstat('a')
846
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
847
state._dirblock_state)
848
873
state._observed_sha1(entry, "foo", statvalue)
849
874
self.assertEqual(oldval, entry[1][0][1])
850
875
self.assertEqual(oldstat, entry[1][0][4])
851
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
852
state._dirblock_state)
854
877
def test_update_entry(self):
855
878
state, _ = self.get_state_with_a()
880
903
stat_value=stat_value)
881
904
self.assertEqual(None, link_or_sha1)
883
# The dirblock entry should not have computed or cached the file's
884
# sha1, but it did update the files' st_size. However, this is not
885
# 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)
886
907
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
888
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
909
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
889
910
state._dirblock_state)
890
911
mode = stat_value.st_mode
891
912
self.assertEqual([('is_exec', mode, False)], state._log)
968
988
# Dirblock is not updated (the link is too new)
969
989
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
971
# The file entry turned into a symlink, that is considered
972
# HASH modified worthy.
973
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
991
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
974
992
state._dirblock_state)
976
994
# Because the stat_value looks new, we should re-read the target
978
995
link_or_sha1 = self.update_entry(state, entry, abspath='a',
979
996
stat_value=stat_value)
980
997
self.assertEqual('target', link_or_sha1)
981
self.assertEqual([('read_link', 'a', '')], state._log)
998
self.assertEqual([('read_link', 'a', ''),
999
('read_link', 'a', ''),
982
1001
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
985
1003
state.adjust_time(+20) # Skip into the future, all files look old
987
1004
link_or_sha1 = self.update_entry(state, entry, abspath='a',
988
1005
stat_value=stat_value)
989
# The symlink stayed a symlink. So while it is new enough to cache, we
990
# don't bother setting the flag, because it is not really worth saving
991
# (when we stat the symlink, we'll have paged in the target.)
992
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
993
state._dirblock_state)
994
1006
self.assertEqual('target', link_or_sha1)
995
1007
# We need to re-read the link because only now can we cache it
996
self.assertEqual([('read_link', 'a', '')], state._log)
1008
self.assertEqual([('read_link', 'a', ''),
1009
('read_link', 'a', ''),
1010
('read_link', 'a', ''),
997
1012
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1001
1015
# Another call won't re-read the link
1002
self.assertEqual([], state._log)
1016
self.assertEqual([('read_link', 'a', ''),
1017
('read_link', 'a', ''),
1018
('read_link', 'a', ''),
1003
1020
link_or_sha1 = self.update_entry(state, entry, abspath='a',
1004
1021
stat_value=stat_value)
1005
1022
self.assertEqual('target', link_or_sha1)
1020
1037
self.build_tree(['a/'])
1021
1038
state.adjust_time(+20)
1022
1039
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1023
# a/ used to be a file, but is now a directory, worth saving
1024
1040
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1025
1041
state._dirblock_state)
1027
1043
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1028
1044
state._dirblock_state)
1029
# No changes to a/ means not worth saving.
1030
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1031
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1032
state._dirblock_state)
1033
# Change the last-modified time for the directory
1034
t = time.time() - 100.0
1036
os.utime('a', (t, t))
1038
# It looks like Win32 + FAT doesn't allow to change times on a dir.
1039
raise tests.TestSkipped("can't update mtime of a dir on FAT")
1040
saved_packed_stat = entry[1][0][-1]
1041
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1042
# We *do* go ahead and update the information in the dirblocks, but we
1043
# don't bother setting IN_MEMORY_MODIFIED because it is trivial to
1045
self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1045
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1046
1046
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1047
1047
state._dirblock_state)
1299
1301
self.assertEqual(sorted(expected), sorted(file_ids))
1301
def test_exceptions_raised(self):
1302
# This is a direct test of bug #495023, it relies on osutils.is_inside
1303
# getting called in an inner function. Which makes it a bit brittle,
1304
# but at least it does reproduce the bug.
1305
tree = self.make_branch_and_tree('tree')
1306
self.build_tree(['tree/file', 'tree/dir/', 'tree/dir/sub',
1307
'tree/dir2/', 'tree/dir2/sub2'])
1308
tree.add(['file', 'dir', 'dir/sub', 'dir2', 'dir2/sub2'])
1309
tree.commit('first commit')
1311
self.addCleanup(tree.unlock)
1312
basis_tree = tree.basis_tree()
1313
def is_inside_raises(*args, **kwargs):
1314
raise RuntimeError('stop this')
1315
self.overrideAttr(osutils, 'is_inside', is_inside_raises)
1316
self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1318
1303
def test_simple_changes(self):
1319
1304
tree = self.make_branch_and_tree('tree')
1320
1305
self.build_tree(['tree/file'])