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_pyx
36
has_dirstate_helpers_pyx = True
38
has_dirstate_helpers_pyx = False
41
class _CompiledDirstateHelpersFeature(tests.Feature):
43
return has_dirstate_helpers_pyx
45
def feature_name(self):
46
return 'bzrlib._dirstate_helpers_pyx'
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_pyx:
60
pyrex_scenario = ('dirstate_Pyrex',
61
{'update_entry': _dirstate_helpers_pyx.update_entry})
62
ue_scenarios.append(pyrex_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_pyx:
75
{'_process_entry': _dirstate_helpers_pyx.ProcessEntryC})
76
pe_scenarios.append(pyrex_scenario)
77
process_entry_tests, remaining_tests = tests.split_suite_by_condition(
78
remaining_tests, tests.condition_isinstance(TestProcessEntry))
79
tests.multiply_tests(process_entry_tests,
80
tests.multiply_scenarios(dir_reader_scenarios,
84
dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
85
remaining_tests, tests.condition_isinstance(
86
test_dirstate.TestCaseWithDirState))
87
tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
88
suite.addTest(remaining_tests)
61
93
class TestBisectPathMixin(object):
714
744
def test_trailing_garbage(self):
715
745
tree, state, expected = self.create_basic_dirstate()
716
# On Unix, we can write extra data as long as we haven't read yet, but
717
# on Win32, if you've opened the file with FILE_SHARE_READ, trying to
718
# open it in append mode will fail.
746
# We can modify the file as long as it hasn't been read yet.
720
747
f = open('dirstate', 'ab')
722
749
# Add bogus trailing garbage
723
750
f.write('bogus\n')
727
753
e = self.assertRaises(errors.DirstateCorrupt,
728
754
state._read_dirblocks_if_needed)
729
755
# Make sure we mention the bogus characters in the error
751
777
def test_bisect_dirblock(self):
752
if compiled_dirstate_helpers_feature.available():
778
if CompiledDirstateHelpersFeature.available():
753
779
from bzrlib._dirstate_helpers_pyx import bisect_dirblock
755
781
from bzrlib._dirstate_helpers_py import bisect_dirblock
756
782
self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
758
784
def test__bisect_path_left(self):
759
if compiled_dirstate_helpers_feature.available():
785
if CompiledDirstateHelpersFeature.available():
760
786
from bzrlib._dirstate_helpers_pyx import _bisect_path_left
762
788
from bzrlib._dirstate_helpers_py import _bisect_path_left
763
789
self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
765
791
def test__bisect_path_right(self):
766
if compiled_dirstate_helpers_feature.available():
792
if CompiledDirstateHelpersFeature.available():
767
793
from bzrlib._dirstate_helpers_pyx import _bisect_path_right
769
795
from bzrlib._dirstate_helpers_py import _bisect_path_right
770
796
self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
772
798
def test_cmp_by_dirs(self):
773
if compiled_dirstate_helpers_feature.available():
799
if CompiledDirstateHelpersFeature.available():
774
800
from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
776
802
from bzrlib._dirstate_helpers_py import cmp_by_dirs
777
803
self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
779
805
def test__read_dirblocks(self):
780
if compiled_dirstate_helpers_feature.available():
806
if CompiledDirstateHelpersFeature.available():
781
807
from bzrlib._dirstate_helpers_pyx import _read_dirblocks
783
809
from bzrlib._dirstate_helpers_py import _read_dirblocks
784
810
self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
786
812
def test_update_entry(self):
787
if compiled_dirstate_helpers_feature.available():
813
if CompiledDirstateHelpersFeature.available():
788
814
from bzrlib._dirstate_helpers_pyx import update_entry
790
816
from bzrlib.dirstate import update_entry
791
817
self.assertIs(update_entry, dirstate.update_entry)
793
819
def test_process_entry(self):
794
if compiled_dirstate_helpers_feature.available():
820
if CompiledDirstateHelpersFeature.available():
795
821
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
796
822
self.assertIs(ProcessEntryC, dirstate._process_entry)
802
828
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
803
829
"""Test the DirState.update_entry functions"""
805
scenarios = multiply_scenarios(
806
dir_reader_scenarios(), ue_scenarios)
808
831
# Set by load_tests
809
832
update_entry = None
812
835
super(TestUpdateEntry, self).setUp()
813
self.overrideAttr(dirstate, 'update_entry', self.update_entry)
836
orig = dirstate.update_entry
838
dirstate.update_entry = orig
839
self.addCleanup(cleanup)
840
dirstate.update_entry = self.update_entry
815
842
def get_state_with_a(self):
816
843
"""Create a DirState tracking a single object named 'a'"""
823
850
def test_observed_sha1_cachable(self):
824
851
state, entry = self.get_state_with_a()
826
852
atime = time.time() - 10
827
853
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)
854
statvalue = os.lstat('a')
855
statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
856
statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
832
857
state._observed_sha1(entry, "foo", statvalue)
833
858
self.assertEqual('foo', entry[1][0][1])
834
859
packed_stat = dirstate.pack_stat(statvalue)
835
860
self.assertEqual(packed_stat, entry[1][0][4])
836
self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
837
state._dirblock_state)
839
862
def test_observed_sha1_not_cachable(self):
840
863
state, entry = self.get_state_with_a()
842
864
oldval = entry[1][0][1]
843
865
oldstat = entry[1][0][4]
844
866
self.build_tree(['a'])
845
867
statvalue = os.lstat('a')
846
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
847
state._dirblock_state)
848
868
state._observed_sha1(entry, "foo", statvalue)
849
869
self.assertEqual(oldval, entry[1][0][1])
850
870
self.assertEqual(oldstat, entry[1][0][4])
851
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
852
state._dirblock_state)
854
872
def test_update_entry(self):
855
873
state, _ = self.get_state_with_a()
880
898
stat_value=stat_value)
881
899
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
901
# The dirblock entry should not have cached the file's sha1 (too new)
886
902
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
888
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
904
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
889
905
state._dirblock_state)
890
906
mode = stat_value.st_mode
891
907
self.assertEqual([('is_exec', mode, False)], state._log)
903
920
stat_value=stat_value)
904
921
self.assertEqual([('is_exec', mode, False)], state._log)
905
922
self.assertEqual(None, link_or_sha1)
906
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
923
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
907
924
state._dirblock_state)
908
925
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
919
936
self.assertEqual([('is_exec', mode, False)], state._log)
920
937
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
922
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
923
state._dirblock_state)
925
940
# If the file is no longer new, and the clock has been moved forward
926
941
# sufficiently, it will cache the sha.
968
983
# Dirblock is not updated (the link is too new)
969
984
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,
986
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
974
987
state._dirblock_state)
976
989
# Because the stat_value looks new, we should re-read the target
978
990
link_or_sha1 = self.update_entry(state, entry, abspath='a',
979
991
stat_value=stat_value)
980
992
self.assertEqual('target', link_or_sha1)
981
self.assertEqual([('read_link', 'a', '')], state._log)
993
self.assertEqual([('read_link', 'a', ''),
994
('read_link', 'a', ''),
982
996
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
985
998
state.adjust_time(+20) # Skip into the future, all files look old
987
999
link_or_sha1 = self.update_entry(state, entry, abspath='a',
988
1000
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
1001
self.assertEqual('target', link_or_sha1)
995
1002
# We need to re-read the link because only now can we cache it
996
self.assertEqual([('read_link', 'a', '')], state._log)
1003
self.assertEqual([('read_link', 'a', ''),
1004
('read_link', 'a', ''),
1005
('read_link', 'a', ''),
997
1007
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1001
1010
# Another call won't re-read the link
1002
self.assertEqual([], state._log)
1011
self.assertEqual([('read_link', 'a', ''),
1012
('read_link', 'a', ''),
1013
('read_link', 'a', ''),
1003
1015
link_or_sha1 = self.update_entry(state, entry, abspath='a',
1004
1016
stat_value=stat_value)
1005
1017
self.assertEqual('target', link_or_sha1)
1020
1032
self.build_tree(['a/'])
1021
1033
state.adjust_time(+20)
1022
1034
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
1035
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1025
1036
state._dirblock_state)
1027
1038
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1028
1039
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])
1040
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1046
1041
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1047
1042
state._dirblock_state)
1281
1276
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1283
scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
1285
1278
# Set by load_tests
1286
1279
_process_entry = None
1288
1281
def setUp(self):
1289
1282
super(TestProcessEntry, self).setUp()
1290
self.overrideAttr(dirstate, '_process_entry', self._process_entry)
1283
orig = dirstate._process_entry
1285
dirstate._process_entry = orig
1286
self.addCleanup(cleanup)
1287
dirstate._process_entry = self._process_entry
1292
1289
def assertChangedFileIds(self, expected, tree):
1293
1290
tree.lock_read()
1299
1296
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
1298
def test_simple_changes(self):
1319
1299
tree = self.make_branch_and_tree('tree')
1320
1300
self.build_tree(['tree/file'])