~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

  • Committer: Martin
  • Date: 2010-05-16 15:18:43 UTC
  • mfrom: (5235 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5239.
  • Revision ID: gzlist@googlemail.com-20100516151843-lu53u7caehm3ie3i
Merge bzr.dev to resolve conflicts in NEWS and _chk_map_pyx

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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
23
23
    dirstate,
24
24
    errors,
25
25
    inventory,
 
26
    memorytree,
26
27
    osutils,
27
28
    revision as _mod_revision,
 
29
    tests,
28
30
    )
29
 
from bzrlib.memorytree import MemoryTree
30
 
from bzrlib.tests import (
31
 
        SymlinkFeature,
32
 
        TestCase,
33
 
        TestCaseInTempDir,
34
 
        TestCaseWithTransport,
35
 
        )
 
31
from bzrlib.tests import test_osutils
36
32
 
37
33
 
38
34
# TODO:
48
44
# set_path_id  setting id when state is in memory modified
49
45
 
50
46
 
51
 
class TestCaseWithDirState(TestCaseWithTransport):
 
47
def load_tests(basic_tests, module, loader):
 
48
    suite = loader.suiteClass()
 
49
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
 
50
        basic_tests, tests.condition_isinstance(TestCaseWithDirState))
 
51
    tests.multiply_tests(dir_reader_tests,
 
52
                         test_osutils.dir_reader_scenarios(), suite)
 
53
    suite.addTest(remaining_tests)
 
54
    return suite
 
55
 
 
56
 
 
57
class TestCaseWithDirState(tests.TestCaseWithTransport):
52
58
    """Helper functions for creating DirState objects with various content."""
53
59
 
 
60
    # Set by load_tests
 
61
    _dir_reader_class = None
 
62
    _native_to_unicode = None # Not used yet
 
63
 
 
64
    def setUp(self):
 
65
        tests.TestCaseWithTransport.setUp(self)
 
66
 
 
67
        self.overrideAttr(osutils,
 
68
                          '_selected_dir_reader', self._dir_reader_class())
 
69
 
54
70
    def create_empty_dirstate(self):
55
71
        """Return a locked but empty dirstate"""
56
72
        state = dirstate.DirState.initialize('dirstate')
397
413
            (('', '', tree.get_root_id()), # common details
398
414
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
399
415
              ('d', '', 0, False, rev_id), # first parent details
400
 
              ('d', '', 0, False, rev_id2), # second parent details
 
416
              ('d', '', 0, False, rev_id), # second parent details
401
417
             ])])
402
418
        state = dirstate.DirState.from_tree(tree, 'dirstate')
403
419
        self.check_state_with_reopen(expected_result, state)
478
494
            (('', '', tree.get_root_id()), # common details
479
495
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
480
496
              ('d', '', 0, False, rev_id), # first parent details
481
 
              ('d', '', 0, False, rev_id2), # second parent details
 
497
              ('d', '', 0, False, rev_id), # second parent details
482
498
             ]),
483
499
            (('', 'a file', 'a-file-id'), # common
484
500
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
805
821
        finally:
806
822
            tree.unlock()
807
823
 
808
 
 
809
824
    def test_set_state_from_inventory_mixed_paths(self):
810
825
        tree1 = self.make_branch_and_tree('tree1')
811
826
        self.build_tree(['tree1/a/', 'tree1/a/b/', 'tree1/a-b/',
852
867
        state = dirstate.DirState.initialize('dirstate')
853
868
        try:
854
869
            # check precondition to be sure the state does change appropriately.
855
 
            self.assertEqual(
856
 
                [(('', '', 'TREE_ROOT'), [('d', '', 0, False,
857
 
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])],
858
 
                list(state._iter_entries()))
859
 
            state.set_path_id('', 'foobarbaz')
860
 
            expected_rows = [
861
 
                (('', '', 'foobarbaz'), [('d', '', 0, False,
862
 
                   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')])]
 
870
            root_entry = (('', '', 'TREE_ROOT'), [('d', '', 0, False, 'x'*32)])
 
871
            self.assertEqual([root_entry], list(state._iter_entries()))
 
872
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
 
873
            self.assertEqual(root_entry,
 
874
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
 
875
            self.assertEqual((None, None),
 
876
                             state._get_entry(0, fileid_utf8='second-root-id'))
 
877
            state.set_path_id('', 'second-root-id')
 
878
            new_root_entry = (('', '', 'second-root-id'),
 
879
                              [('d', '', 0, False, 'x'*32)])
 
880
            expected_rows = [new_root_entry]
863
881
            self.assertEqual(expected_rows, list(state._iter_entries()))
 
882
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
 
883
            self.assertEqual(new_root_entry, 
 
884
                             state._get_entry(0, fileid_utf8='second-root-id'))
 
885
            self.assertEqual((None, None),
 
886
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
864
887
            # should work across save too
865
888
            state.save()
866
889
        finally:
884
907
        state._validate()
885
908
        try:
886
909
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
887
 
            state.set_path_id('', 'foobarbaz')
 
910
            root_entry = (('', '', 'TREE_ROOT'),
 
911
                          [('d', '', 0, False, 'x'*32),
 
912
                           ('d', '', 0, False, 'parent-revid')])
 
913
            self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
 
914
            self.assertEqual(root_entry,
 
915
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
 
916
            self.assertEqual((None, None),
 
917
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
 
918
            state.set_path_id('', 'Asecond-root-id')
888
919
            state._validate()
889
920
            # now see that it is what we expected
890
 
            expected_rows = [
891
 
                (('', '', 'TREE_ROOT'),
892
 
                    [('a', '', 0, False, ''),
893
 
                     ('d', '', 0, False, 'parent-revid'),
894
 
                     ]),
895
 
                (('', '', 'foobarbaz'),
896
 
                    [('d', '', 0, False, ''),
897
 
                     ('a', '', 0, False, ''),
898
 
                     ]),
899
 
                ]
 
921
            old_root_entry = (('', '', 'TREE_ROOT'),
 
922
                              [('a', '', 0, False, ''),
 
923
                               ('d', '', 0, False, 'parent-revid')])
 
924
            new_root_entry = (('', '', 'Asecond-root-id'),
 
925
                              [('d', '', 0, False, ''),
 
926
                               ('a', '', 0, False, '')])
 
927
            expected_rows = [new_root_entry, old_root_entry]
900
928
            state._validate()
901
929
            self.assertEqual(expected_rows, list(state._iter_entries()))
 
930
            self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
 
931
            self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
 
932
            self.assertEqual((None, None),
 
933
                             state._get_entry(0, fileid_utf8='TREE_ROOT'))
 
934
            self.assertEqual(old_root_entry,
 
935
                             state._get_entry(1, fileid_utf8='TREE_ROOT'))
 
936
            self.assertEqual(new_root_entry,
 
937
                             state._get_entry(0, fileid_utf8='Asecond-root-id'))
 
938
            self.assertEqual((None, None),
 
939
                             state._get_entry(1, fileid_utf8='Asecond-root-id'))
902
940
            # should work across save too
903
941
            state.save()
904
942
        finally:
920
958
        finally:
921
959
            state.unlock()
922
960
 
923
 
 
924
961
    def test_set_parent_trees_no_content(self):
925
962
        # set_parent_trees is a slow but important api to support.
926
963
        tree1 = self.make_branch_and_memory_tree('tree1')
931
968
        finally:
932
969
            tree1.unlock()
933
970
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
934
 
        tree2 = MemoryTree.create_on_branch(branch2)
 
971
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
935
972
        tree2.lock_write()
936
973
        try:
937
974
            revid2 = tree2.commit('foo')
980
1017
                [(('', '', root_id), [
981
1018
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
982
1019
                  ('d', '', 0, False, revid1),
983
 
                  ('d', '', 0, False, revid2)
 
1020
                  ('d', '', 0, False, revid1)
984
1021
                  ])],
985
1022
                list(state._iter_entries()))
986
1023
        finally:
1001
1038
        finally:
1002
1039
            tree1.unlock()
1003
1040
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
1004
 
        tree2 = MemoryTree.create_on_branch(branch2)
 
1041
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
1005
1042
        tree2.lock_write()
1006
1043
        try:
1007
1044
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
1014
1051
            (('', '', root_id), [
1015
1052
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
1016
1053
             ('d', '', 0, False, revid1.encode('utf8')),
1017
 
             ('d', '', 0, False, revid2.encode('utf8'))
 
1054
             ('d', '', 0, False, revid1.encode('utf8'))
1018
1055
             ]),
1019
1056
            (('', 'a file', 'file-id'), [
1020
1057
             ('a', '', 0, False, ''),
1066
1103
            state.unlock()
1067
1104
        state = dirstate.DirState.on_file('dirstate')
1068
1105
        state.lock_read()
1069
 
        try:
1070
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1071
 
        finally:
1072
 
            state.unlock()
 
1106
        self.addCleanup(state.unlock)
 
1107
        self.assertEqual(expected_entries, list(state._iter_entries()))
1073
1108
 
1074
1109
    def test_add_path_to_unversioned_directory(self):
1075
1110
        """Adding a path to an unversioned directory should error.
1080
1115
        """
1081
1116
        self.build_tree(['unversioned/', 'unversioned/a file'])
1082
1117
        state = dirstate.DirState.initialize('dirstate')
1083
 
        try:
1084
 
            self.assertRaises(errors.NotVersionedError, state.add,
1085
 
                'unversioned/a file', 'a-file-id', 'file', None, None)
1086
 
        finally:
1087
 
            state.unlock()
 
1118
        self.addCleanup(state.unlock)
 
1119
        self.assertRaises(errors.NotVersionedError, state.add,
 
1120
                          'unversioned/a file', 'a-file-id', 'file', None, None)
1088
1121
 
1089
1122
    def test_add_directory_to_root_no_parents_all_data(self):
1090
1123
        # The most trivial addition of a dir is when there are no parents and
1110
1143
            state.unlock()
1111
1144
        state = dirstate.DirState.on_file('dirstate')
1112
1145
        state.lock_read()
 
1146
        self.addCleanup(state.unlock)
1113
1147
        state._validate()
1114
 
        try:
1115
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1116
 
        finally:
1117
 
            state.unlock()
 
1148
        self.assertEqual(expected_entries, list(state._iter_entries()))
1118
1149
 
1119
 
    def test_add_symlink_to_root_no_parents_all_data(self):
 
1150
    def _test_add_symlink_to_root_no_parents_all_data(self, link_name, target):
1120
1151
        # The most trivial addition of a symlink when there are no parents and
1121
1152
        # its in the root and all data about the file is supplied
1122
1153
        # bzr doesn't support fake symlinks on windows, yet.
1123
 
        self.requireFeature(SymlinkFeature)
1124
 
        os.symlink('target', 'a link')
1125
 
        stat = os.lstat('a link')
 
1154
        self.requireFeature(tests.SymlinkFeature)
 
1155
        os.symlink(target, link_name)
 
1156
        stat = os.lstat(link_name)
1126
1157
        expected_entries = [
1127
1158
            (('', '', 'TREE_ROOT'), [
1128
1159
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1129
1160
             ]),
1130
 
            (('', 'a link', 'a link id'), [
1131
 
             ('l', 'target', 6, False, dirstate.pack_stat(stat)), # current tree
 
1161
            (('', link_name.encode('UTF-8'), 'a link id'), [
 
1162
             ('l', target.encode('UTF-8'), stat[6],
 
1163
              False, dirstate.pack_stat(stat)), # current tree
1132
1164
             ]),
1133
1165
            ]
1134
1166
        state = dirstate.DirState.initialize('dirstate')
1135
1167
        try:
1136
 
            state.add('a link', 'a link id', 'symlink', stat, 'target')
 
1168
            state.add(link_name, 'a link id', 'symlink', stat,
 
1169
                      target.encode('UTF-8'))
1137
1170
            # having added it, it should be in the output of iter_entries.
1138
1171
            self.assertEqual(expected_entries, list(state._iter_entries()))
1139
1172
            # saving and reloading should not affect this.
1142
1175
            state.unlock()
1143
1176
        state = dirstate.DirState.on_file('dirstate')
1144
1177
        state.lock_read()
1145
 
        try:
1146
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1147
 
        finally:
1148
 
            state.unlock()
 
1178
        self.addCleanup(state.unlock)
 
1179
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
1180
 
 
1181
    def test_add_symlink_to_root_no_parents_all_data(self):
 
1182
        self._test_add_symlink_to_root_no_parents_all_data('a link', 'target')
 
1183
 
 
1184
    def test_add_symlink_unicode_to_root_no_parents_all_data(self):
 
1185
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1186
        self._test_add_symlink_to_root_no_parents_all_data(
 
1187
            u'\N{Euro Sign}link', u'targ\N{Euro Sign}et')
1149
1188
 
1150
1189
    def test_add_directory_and_child_no_parents_all_data(self):
1151
1190
        # after adding a directory, we should be able to add children to it.
1176
1215
            state.unlock()
1177
1216
        state = dirstate.DirState.on_file('dirstate')
1178
1217
        state.lock_read()
1179
 
        try:
1180
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1181
 
        finally:
1182
 
            state.unlock()
 
1218
        self.addCleanup(state.unlock)
 
1219
        self.assertEqual(expected_entries, list(state._iter_entries()))
1183
1220
 
1184
1221
    def test_add_tree_reference(self):
1185
1222
        # make a dirstate and add a tree reference
1199
1236
            state.unlock()
1200
1237
        # now check we can read it back
1201
1238
        state.lock_read()
 
1239
        self.addCleanup(state.unlock)
1202
1240
        state._validate()
1203
 
        try:
1204
 
            entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1205
 
            self.assertEqual(entry, entry2)
1206
 
            self.assertEqual(entry, expected_entry)
1207
 
            # and lookup by id should work too
1208
 
            entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1209
 
            self.assertEqual(entry, expected_entry)
1210
 
        finally:
1211
 
            state.unlock()
 
1241
        entry2 = state._get_entry(0, 'subdir-id', 'subdir')
 
1242
        self.assertEqual(entry, entry2)
 
1243
        self.assertEqual(entry, expected_entry)
 
1244
        # and lookup by id should work too
 
1245
        entry2 = state._get_entry(0, fileid_utf8='subdir-id')
 
1246
        self.assertEqual(entry, expected_entry)
1212
1247
 
1213
1248
    def test_add_forbidden_names(self):
1214
1249
        state = dirstate.DirState.initialize('dirstate')
1218
1253
        self.assertRaises(errors.BzrError,
1219
1254
            state.add, '..', 'ass-id', 'directory', None, None)
1220
1255
 
 
1256
    def test_set_state_with_rename_b_a_bug_395556(self):
 
1257
        # bug 395556 uncovered a bug where the dirstate ends up with a false
 
1258
        # relocation record - in a tree with no parents there should be no
 
1259
        # absent or relocated records. This then leads to further corruption
 
1260
        # when a commit occurs, as the incorrect relocation gathers an
 
1261
        # incorrect absent in tree 1, and future changes go to pot.
 
1262
        tree1 = self.make_branch_and_tree('tree1')
 
1263
        self.build_tree(['tree1/b'])
 
1264
        tree1.lock_write()
 
1265
        try:
 
1266
            tree1.add(['b'], ['b-id'])
 
1267
            root_id = tree1.get_root_id()
 
1268
            inv = tree1.inventory
 
1269
            state = dirstate.DirState.initialize('dirstate')
 
1270
            try:
 
1271
                # Set the initial state with 'b'
 
1272
                state.set_state_from_inventory(inv)
 
1273
                inv.rename('b-id', root_id, 'a')
 
1274
                # Set the new state with 'a', which currently corrupts.
 
1275
                state.set_state_from_inventory(inv)
 
1276
                expected_result1 = [('', '', root_id, 'd'),
 
1277
                                    ('', 'a', 'b-id', 'f'),
 
1278
                                   ]
 
1279
                values = []
 
1280
                for entry in state._iter_entries():
 
1281
                    values.append(entry[0] + entry[1][0][:1])
 
1282
                self.assertEqual(expected_result1, values)
 
1283
            finally:
 
1284
                state.unlock()
 
1285
        finally:
 
1286
            tree1.unlock()
 
1287
 
1221
1288
 
1222
1289
class TestGetLines(TestCaseWithDirState):
1223
1290
 
1552
1619
            list(state._iter_child_entries(1, '')))
1553
1620
 
1554
1621
 
1555
 
class TestDirstateSortOrder(TestCaseWithTransport):
 
1622
class TestDirstateSortOrder(tests.TestCaseWithTransport):
1556
1623
    """Test that DirState adds entries in the right order."""
1557
1624
 
1558
1625
    def test_add_sorting(self):
1674
1741
            st.st_ino, st.st_mode)
1675
1742
 
1676
1743
 
1677
 
class TestPackStat(TestCaseWithTransport):
 
1744
class TestPackStat(tests.TestCaseWithTransport):
1678
1745
 
1679
1746
    def assertPackStat(self, expected, stat_value):
1680
1747
        """Check the packed and serialized form of a stat value."""
2207
2274
        self.assertEqual(exp_dirblocks, state._dirblocks)
2208
2275
 
2209
2276
 
2210
 
class Test_InvEntryToDetails(TestCaseWithDirState):
 
2277
class Test_InvEntryToDetails(tests.TestCase):
2211
2278
 
2212
2279
    def assertDetails(self, expected, inv_entry):
2213
2280
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
2220
2287
        self.assertIsInstance(tree_data, str)
2221
2288
 
2222
2289
    def test_unicode_symlink(self):
2223
 
        # In general, the code base doesn't support a target that contains
2224
 
        # non-ascii characters. So we just assert tha
2225
 
        inv_entry = inventory.InventoryLink('link-file-id', 'name',
 
2290
        inv_entry = inventory.InventoryLink('link-file-id',
 
2291
                                            u'nam\N{Euro Sign}e',
2226
2292
                                            'link-parent-id')
2227
2293
        inv_entry.revision = 'link-revision-id'
2228
 
        inv_entry.symlink_target = u'link-target'
2229
 
        details = self.assertDetails(('l', 'link-target', 0, False,
2230
 
                                      'link-revision-id'), inv_entry)
2231
 
 
2232
 
 
2233
 
class TestSHA1Provider(TestCaseInTempDir):
 
2294
        target = u'link-targ\N{Euro Sign}t'
 
2295
        inv_entry.symlink_target = target
 
2296
        self.assertDetails(('l', target.encode('UTF-8'), 0, False,
 
2297
                            'link-revision-id'), inv_entry)
 
2298
 
 
2299
 
 
2300
class TestSHA1Provider(tests.TestCaseInTempDir):
2234
2301
 
2235
2302
    def test_sha1provider_is_an_interface(self):
2236
2303
        p = dirstate.SHA1Provider()