~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__dirstate_helpers.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
    errors,
26
26
    osutils,
27
27
    tests,
 
28
    _dirstate_helpers_py,
28
29
    )
29
30
from bzrlib.tests import (
30
31
    test_dirstate,
31
 
    test_osutils,
32
 
    )
33
 
 
34
 
try:
35
 
    from bzrlib import _dirstate_helpers_pyx
36
 
    has_dirstate_helpers_pyx = True
37
 
except ImportError:
38
 
    has_dirstate_helpers_pyx = False
39
 
 
40
 
 
41
 
class _CompiledDirstateHelpersFeature(tests.Feature):
42
 
    def _probe(self):
43
 
        return has_dirstate_helpers_pyx
44
 
 
45
 
    def feature_name(self):
46
 
        return 'bzrlib._dirstate_helpers_pyx'
47
 
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
48
 
 
49
 
 
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
54
 
 
55
 
    dir_reader_scenarios = test_osutils.dir_reader_scenarios()
56
 
 
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,
67
 
                                                  ue_scenarios),
68
 
                         suite)
69
 
 
70
 
    pe_scenarios = [('dirstate_Python',
71
 
                     {'_process_entry': dirstate.ProcessEntryPython})]
72
 
    if has_dirstate_helpers_pyx:
73
 
        pyrex_scenario = (
74
 
            'dirstate_Pyrex',
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,
81
 
                                                  pe_scenarios),
82
 
                         suite)
83
 
 
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)
89
 
 
90
 
    return suite
 
32
    )
 
33
from bzrlib.tests.test_osutils import dir_reader_scenarios
 
34
from bzrlib.tests.scenarios import (
 
35
    load_tests_apply_scenarios,
 
36
    multiply_scenarios,
 
37
    )
 
38
from bzrlib.tests import (
 
39
    features,
 
40
    )
 
41
 
 
42
 
 
43
load_tests = load_tests_apply_scenarios
 
44
 
 
45
 
 
46
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
 
47
    'bzrlib._dirstate_helpers_pyx')
 
48
 
 
49
 
 
50
# FIXME: we should also parametrize against SHA1Provider !
 
51
 
 
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
    ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
 
57
 
 
58
pe_scenarios = [('dirstate_Python',
 
59
    {'_process_entry': dirstate.ProcessEntryPython})]
 
60
if compiled_dirstate_helpers_feature.available():
 
61
    process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
 
62
    pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
 
63
 
 
64
helper_scenarios = [('dirstate_Python', {'helpers': _dirstate_helpers_py})]
 
65
if compiled_dirstate_helpers_feature.available():
 
66
    helper_scenarios.append(('dirstate_Pyrex',
 
67
        {'helpers': compiled_dirstate_helpers_feature.module}))
91
68
 
92
69
 
93
70
class TestBisectPathMixin(object):
259
236
class TestCompiledBisectPathLeft(TestBisectPathLeft):
260
237
    """Run all Bisect Path tests against _bisect_path_lect"""
261
238
 
262
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
239
    _test_needs_features = [compiled_dirstate_helpers_feature]
263
240
 
264
241
    def get_bisect_path(self):
265
242
        from bzrlib._dirstate_helpers_pyx import _bisect_path_left
280
257
class TestCompiledBisectPathRight(TestBisectPathRight):
281
258
    """Run all Bisect Path tests against _bisect_path_right"""
282
259
 
283
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
260
    _test_needs_features = [compiled_dirstate_helpers_feature]
284
261
 
285
262
    def get_bisect_path(self):
286
263
        from bzrlib._dirstate_helpers_pyx import _bisect_path_right
392
369
    compiled version.
393
370
    """
394
371
 
395
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
372
    _test_needs_features = [compiled_dirstate_helpers_feature]
396
373
 
397
374
    def get_bisect_dirblock(self):
398
375
        from bzrlib._dirstate_helpers_pyx import bisect_dirblock
514
491
class TestCompiledCmpByDirs(TestCmpByDirs):
515
492
    """Test the pyrex implementation of cmp_by_dirs"""
516
493
 
517
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
494
    _test_needs_features = [compiled_dirstate_helpers_feature]
518
495
 
519
496
    def get_cmp_by_dirs(self):
520
497
        from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
665
642
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
666
643
    """Test the pyrex implementation of _cmp_path_by_dirblock"""
667
644
 
668
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
645
    _test_needs_features = [compiled_dirstate_helpers_feature]
669
646
 
670
647
    def get_cmp_by_dirs(self):
671
648
        from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
675
652
class TestMemRChr(tests.TestCase):
676
653
    """Test memrchr functionality"""
677
654
 
678
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
655
    _test_needs_features = [compiled_dirstate_helpers_feature]
679
656
 
680
657
    def assertMemRChr(self, expected, s, c):
681
658
        from bzrlib._dirstate_helpers_pyx import _py_memrchr
725
702
    implementation.
726
703
    """
727
704
 
 
705
    # inherits scenarios from test_dirstate
 
706
 
728
707
    def get_read_dirblocks(self):
729
708
        from bzrlib._dirstate_helpers_py import _read_dirblocks
730
709
        return _read_dirblocks
743
722
 
744
723
    def test_trailing_garbage(self):
745
724
        tree, state, expected = self.create_basic_dirstate()
746
 
        # On Linux, we can write extra data as long as we haven't read yet, but
 
725
        # On Unix, we can write extra data as long as we haven't read yet, but
747
726
        # on Win32, if you've opened the file with FILE_SHARE_READ, trying to
748
727
        # open it in append mode will fail.
749
728
        state.unlock()
763
742
class TestCompiledReadDirblocks(TestReadDirblocks):
764
743
    """Test the pyrex implementation of _read_dirblocks"""
765
744
 
766
 
    _test_needs_features = [CompiledDirstateHelpersFeature]
 
745
    _test_needs_features = [compiled_dirstate_helpers_feature]
767
746
 
768
747
    def get_read_dirblocks(self):
769
748
        from bzrlib._dirstate_helpers_pyx import _read_dirblocks
779
758
    """
780
759
 
781
760
    def test_bisect_dirblock(self):
782
 
        if CompiledDirstateHelpersFeature.available():
 
761
        if compiled_dirstate_helpers_feature.available():
783
762
            from bzrlib._dirstate_helpers_pyx import bisect_dirblock
784
763
        else:
785
764
            from bzrlib._dirstate_helpers_py import bisect_dirblock
786
765
        self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
787
766
 
788
767
    def test__bisect_path_left(self):
789
 
        if CompiledDirstateHelpersFeature.available():
 
768
        if compiled_dirstate_helpers_feature.available():
790
769
            from bzrlib._dirstate_helpers_pyx import _bisect_path_left
791
770
        else:
792
771
            from bzrlib._dirstate_helpers_py import _bisect_path_left
793
772
        self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
794
773
 
795
774
    def test__bisect_path_right(self):
796
 
        if CompiledDirstateHelpersFeature.available():
 
775
        if compiled_dirstate_helpers_feature.available():
797
776
            from bzrlib._dirstate_helpers_pyx import _bisect_path_right
798
777
        else:
799
778
            from bzrlib._dirstate_helpers_py import _bisect_path_right
800
779
        self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
801
780
 
802
781
    def test_cmp_by_dirs(self):
803
 
        if CompiledDirstateHelpersFeature.available():
 
782
        if compiled_dirstate_helpers_feature.available():
804
783
            from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
805
784
        else:
806
785
            from bzrlib._dirstate_helpers_py import cmp_by_dirs
807
786
        self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
808
787
 
809
788
    def test__read_dirblocks(self):
810
 
        if CompiledDirstateHelpersFeature.available():
 
789
        if compiled_dirstate_helpers_feature.available():
811
790
            from bzrlib._dirstate_helpers_pyx import _read_dirblocks
812
791
        else:
813
792
            from bzrlib._dirstate_helpers_py import _read_dirblocks
814
793
        self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
815
794
 
816
795
    def test_update_entry(self):
817
 
        if CompiledDirstateHelpersFeature.available():
 
796
        if compiled_dirstate_helpers_feature.available():
818
797
            from bzrlib._dirstate_helpers_pyx import update_entry
819
798
        else:
820
799
            from bzrlib.dirstate import update_entry
821
800
        self.assertIs(update_entry, dirstate.update_entry)
822
801
 
823
802
    def test_process_entry(self):
824
 
        if CompiledDirstateHelpersFeature.available():
 
803
        if compiled_dirstate_helpers_feature.available():
825
804
            from bzrlib._dirstate_helpers_pyx import ProcessEntryC
826
805
            self.assertIs(ProcessEntryC, dirstate._process_entry)
827
806
        else:
832
811
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
833
812
    """Test the DirState.update_entry functions"""
834
813
 
 
814
    scenarios = multiply_scenarios(
 
815
        dir_reader_scenarios(), ue_scenarios)
 
816
 
835
817
    # Set by load_tests
836
818
    update_entry = None
837
819
 
838
820
    def setUp(self):
839
821
        super(TestUpdateEntry, self).setUp()
840
 
        orig = dirstate.update_entry
841
 
        def cleanup():
842
 
            dirstate.update_entry = orig
843
 
        self.addCleanup(cleanup)
844
 
        dirstate.update_entry = self.update_entry
 
822
        self.overrideAttr(dirstate, 'update_entry', self.update_entry)
845
823
 
846
824
    def get_state_with_a(self):
847
825
        """Create a DirState tracking a single object named 'a'"""
853
831
 
854
832
    def test_observed_sha1_cachable(self):
855
833
        state, entry = self.get_state_with_a()
 
834
        state.save()
856
835
        atime = time.time() - 10
857
836
        self.build_tree(['a'])
858
 
        statvalue = os.lstat('a')
859
 
        statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
860
 
            statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
 
837
        statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
 
838
        statvalue.st_mtime = statvalue.st_ctime = atime
 
839
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
840
                         state._dirblock_state)
861
841
        state._observed_sha1(entry, "foo", statvalue)
862
842
        self.assertEqual('foo', entry[1][0][1])
863
843
        packed_stat = dirstate.pack_stat(statvalue)
864
844
        self.assertEqual(packed_stat, entry[1][0][4])
 
845
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
846
                         state._dirblock_state)
865
847
 
866
848
    def test_observed_sha1_not_cachable(self):
867
849
        state, entry = self.get_state_with_a()
 
850
        state.save()
868
851
        oldval = entry[1][0][1]
869
852
        oldstat = entry[1][0][4]
870
853
        self.build_tree(['a'])
871
854
        statvalue = os.lstat('a')
 
855
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
856
                         state._dirblock_state)
872
857
        state._observed_sha1(entry, "foo", statvalue)
873
858
        self.assertEqual(oldval, entry[1][0][1])
874
859
        self.assertEqual(oldstat, entry[1][0][4])
 
860
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
861
                         state._dirblock_state)
875
862
 
876
863
    def test_update_entry(self):
877
864
        state, _ = self.get_state_with_a()
902
889
                                          stat_value=stat_value)
903
890
        self.assertEqual(None, link_or_sha1)
904
891
 
905
 
        # The dirblock entry should not have cached the file's sha1 (too new)
 
892
        # The dirblock entry should not have computed or cached the file's
 
893
        # sha1, but it did update the files' st_size. However, this is not
 
894
        # worth writing a dirstate file for, so we leave the state UNMODIFIED
906
895
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
907
896
                         entry[1][0])
908
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
897
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
909
898
                         state._dirblock_state)
910
899
        mode = stat_value.st_mode
911
900
        self.assertEqual([('is_exec', mode, False)], state._log)
914
903
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
915
904
                         state._dirblock_state)
916
905
 
917
 
        # If we do it again right away, we don't know if the file has changed
918
 
        # so we will re-read the file. Roll the clock back so the file is
919
 
        # guaranteed to look too new.
 
906
        # Roll the clock back so the file is guaranteed to look too new. We
 
907
        # should still not compute the sha1.
920
908
        state.adjust_time(-10)
921
909
        del state._log[:]
922
910
 
924
912
                                          stat_value=stat_value)
925
913
        self.assertEqual([('is_exec', mode, False)], state._log)
926
914
        self.assertEqual(None, link_or_sha1)
927
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
915
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
928
916
                         state._dirblock_state)
929
917
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
930
918
                         entry[1][0])
940
928
        self.assertEqual([('is_exec', mode, False)], state._log)
941
929
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
942
930
                         entry[1][0])
 
931
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
932
                         state._dirblock_state)
943
933
 
944
934
        # If the file is no longer new, and the clock has been moved forward
945
935
        # sufficiently, it will cache the sha.
970
960
 
971
961
    def test_update_entry_symlink(self):
972
962
        """Update entry should read symlinks."""
973
 
        self.requireFeature(tests.SymlinkFeature)
 
963
        self.requireFeature(features.SymlinkFeature)
974
964
        state, entry = self.get_state_with_a()
975
965
        state.save()
976
966
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
987
977
        # Dirblock is not updated (the link is too new)
988
978
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
989
979
                         entry[1])
990
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
980
        # The file entry turned into a symlink, that is considered
 
981
        # HASH modified worthy.
 
982
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
991
983
                         state._dirblock_state)
992
984
 
993
985
        # Because the stat_value looks new, we should re-read the target
 
986
        del state._log[:]
994
987
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
995
988
                                          stat_value=stat_value)
996
989
        self.assertEqual('target', link_or_sha1)
997
 
        self.assertEqual([('read_link', 'a', ''),
998
 
                          ('read_link', 'a', ''),
999
 
                         ], state._log)
 
990
        self.assertEqual([('read_link', 'a', '')], state._log)
1000
991
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1001
992
                         entry[1])
 
993
        state.save()
1002
994
        state.adjust_time(+20) # Skip into the future, all files look old
 
995
        del state._log[:]
1003
996
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1004
997
                                          stat_value=stat_value)
 
998
        # The symlink stayed a symlink. So while it is new enough to cache, we
 
999
        # don't bother setting the flag, because it is not really worth saving
 
1000
        # (when we stat the symlink, we'll have paged in the target.)
 
1001
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1002
                         state._dirblock_state)
1005
1003
        self.assertEqual('target', link_or_sha1)
1006
1004
        # We need to re-read the link because only now can we cache it
1007
 
        self.assertEqual([('read_link', 'a', ''),
1008
 
                          ('read_link', 'a', ''),
1009
 
                          ('read_link', 'a', ''),
1010
 
                         ], state._log)
 
1005
        self.assertEqual([('read_link', 'a', '')], state._log)
1011
1006
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
1012
1007
                         entry[1])
1013
1008
 
 
1009
        del state._log[:]
1014
1010
        # Another call won't re-read the link
1015
 
        self.assertEqual([('read_link', 'a', ''),
1016
 
                          ('read_link', 'a', ''),
1017
 
                          ('read_link', 'a', ''),
1018
 
                         ], state._log)
 
1011
        self.assertEqual([], state._log)
1019
1012
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1020
1013
                                          stat_value=stat_value)
1021
1014
        self.assertEqual('target', link_or_sha1)
1036
1029
        self.build_tree(['a/'])
1037
1030
        state.adjust_time(+20)
1038
1031
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1032
        # a/ used to be a file, but is now a directory, worth saving
1039
1033
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1040
1034
                         state._dirblock_state)
1041
1035
        state.save()
1042
1036
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1043
1037
                         state._dirblock_state)
1044
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1038
        # No changes to a/ means not worth saving.
 
1039
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1040
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1041
                         state._dirblock_state)
 
1042
        # Change the last-modified time for the directory
 
1043
        t = time.time() - 100.0
 
1044
        try:
 
1045
            os.utime('a', (t, t))
 
1046
        except OSError:
 
1047
            # It looks like Win32 + FAT doesn't allow to change times on a dir.
 
1048
            raise tests.TestSkipped("can't update mtime of a dir on FAT")
 
1049
        saved_packed_stat = entry[1][0][-1]
 
1050
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1051
        # We *do* go ahead and update the information in the dirblocks, but we
 
1052
        # don't bother setting IN_MEMORY_MODIFIED because it is trivial to
 
1053
        # recompute.
 
1054
        self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1045
1055
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1046
1056
                         state._dirblock_state)
1047
1057
 
1147
1157
 
1148
1158
    def test_update_file_to_symlink(self):
1149
1159
        """File becomes a symlink"""
1150
 
        self.requireFeature(tests.SymlinkFeature)
 
1160
        self.requireFeature(features.SymlinkFeature)
1151
1161
        state, entry = self.get_state_with_a()
1152
1162
        # The file sha1 won't be cached unless the file is old
1153
1163
        state.adjust_time(+10)
1166
1176
 
1167
1177
    def test_update_dir_to_symlink(self):
1168
1178
        """Directory becomes a symlink"""
1169
 
        self.requireFeature(tests.SymlinkFeature)
 
1179
        self.requireFeature(features.SymlinkFeature)
1170
1180
        state, entry = self.get_state_with_a()
1171
1181
        # The symlink target won't be cached if it isn't old
1172
1182
        state.adjust_time(+10)
1176
1186
 
1177
1187
    def test_update_symlink_to_file(self):
1178
1188
        """Symlink becomes a file"""
1179
 
        self.requireFeature(tests.SymlinkFeature)
 
1189
        self.requireFeature(features.SymlinkFeature)
1180
1190
        state, entry = self.get_state_with_a()
1181
1191
        # The symlink and file info won't be cached unless old
1182
1192
        state.adjust_time(+10)
1186
1196
 
1187
1197
    def test_update_symlink_to_dir(self):
1188
1198
        """Symlink becomes a directory"""
1189
 
        self.requireFeature(tests.SymlinkFeature)
 
1199
        self.requireFeature(features.SymlinkFeature)
1190
1200
        state, entry = self.get_state_with_a()
1191
1201
        # The symlink target won't be cached if it isn't old
1192
1202
        state.adjust_time(+10)
1279
1289
 
1280
1290
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1281
1291
 
 
1292
    scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
 
1293
 
1282
1294
    # Set by load_tests
1283
1295
    _process_entry = None
1284
1296
 
1285
1297
    def setUp(self):
1286
1298
        super(TestProcessEntry, self).setUp()
1287
 
        orig = dirstate._process_entry
1288
 
        def cleanup():
1289
 
            dirstate._process_entry = orig
1290
 
        self.addCleanup(cleanup)
1291
 
        dirstate._process_entry = self._process_entry
 
1299
        self.overrideAttr(dirstate, '_process_entry', self._process_entry)
1292
1300
 
1293
1301
    def assertChangedFileIds(self, expected, tree):
1294
1302
        tree.lock_read()
1299
1307
            tree.unlock()
1300
1308
        self.assertEqual(sorted(expected), sorted(file_ids))
1301
1309
 
 
1310
    def test_exceptions_raised(self):
 
1311
        # This is a direct test of bug #495023, it relies on osutils.is_inside
 
1312
        # getting called in an inner function. Which makes it a bit brittle,
 
1313
        # but at least it does reproduce the bug.
 
1314
        tree = self.make_branch_and_tree('tree')
 
1315
        self.build_tree(['tree/file', 'tree/dir/', 'tree/dir/sub',
 
1316
                         'tree/dir2/', 'tree/dir2/sub2'])
 
1317
        tree.add(['file', 'dir', 'dir/sub', 'dir2', 'dir2/sub2'])
 
1318
        tree.commit('first commit')
 
1319
        tree.lock_read()
 
1320
        self.addCleanup(tree.unlock)
 
1321
        basis_tree = tree.basis_tree()
 
1322
        def is_inside_raises(*args, **kwargs):
 
1323
            raise RuntimeError('stop this')
 
1324
        self.overrideAttr(osutils, 'is_inside', is_inside_raises)
 
1325
        self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
 
1326
 
1302
1327
    def test_simple_changes(self):
1303
1328
        tree = self.make_branch_and_tree('tree')
1304
1329
        self.build_tree(['tree/file'])
1318
1343
        state._sha1_provider = UppercaseSHA1Provider()
1319
1344
        self.assertChangedFileIds(['file-id'], tree)
1320
1345
 
 
1346
 
 
1347
class TestPackStat(tests.TestCase):
 
1348
    """Check packed representaton of stat values is robust on all inputs"""
 
1349
 
 
1350
    scenarios = helper_scenarios
 
1351
 
 
1352
    def pack(self, statlike_tuple):
 
1353
        return self.helpers.pack_stat(os.stat_result(statlike_tuple))
 
1354
 
 
1355
    @staticmethod
 
1356
    def unpack_field(packed_string, stat_field):
 
1357
        return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
 
1358
 
 
1359
    def test_result(self):
 
1360
        self.assertEqual("AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
 
1361
            self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
 
1362
 
 
1363
    def test_giant_inode(self):
 
1364
        packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
 
1365
        self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
 
1366
 
 
1367
    def test_giant_size(self):
 
1368
        packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
 
1369
        self.assertEqual(4096, self.unpack_field(packed, "st_size"))
 
1370
 
 
1371
    def test_fractional_mtime(self):
 
1372
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
 
1373
        self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
 
1374
 
 
1375
    def test_ancient_mtime(self):
 
1376
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
 
1377
        self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
 
1378
 
 
1379
    def test_distant_mtime(self):
 
1380
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
 
1381
        self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
 
1382
 
 
1383
    def test_fractional_ctime(self):
 
1384
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
 
1385
        self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
 
1386
 
 
1387
    def test_ancient_ctime(self):
 
1388
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
 
1389
        self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
 
1390
 
 
1391
    def test_distant_ctime(self):
 
1392
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
 
1393
        self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
 
1394
 
 
1395
    def test_negative_dev(self):
 
1396
        packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
 
1397
        self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))