~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

  • Committer: Jelmer Vernooij
  • Date: 2009-04-10 15:58:09 UTC
  • mto: This revision was merged to the branch mainline in revision 4284.
  • Revision ID: jelmer@samba.org-20090410155809-kdibzcjvp7pdb83f
Fix missing import.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 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,
27
26
    osutils,
28
27
    revision as _mod_revision,
29
 
    tests,
30
28
    )
31
 
from bzrlib.tests import test_osutils
 
29
from bzrlib.memorytree import MemoryTree
 
30
from bzrlib.tests import (
 
31
        SymlinkFeature,
 
32
        TestCase,
 
33
        TestCaseInTempDir,
 
34
        TestCaseWithTransport,
 
35
        )
32
36
 
33
37
 
34
38
# TODO:
44
48
# set_path_id  setting id when state is in memory modified
45
49
 
46
50
 
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):
 
51
class TestCaseWithDirState(TestCaseWithTransport):
58
52
    """Helper functions for creating DirState objects with various content."""
59
53
 
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
 
 
70
54
    def create_empty_dirstate(self):
71
55
        """Return a locked but empty dirstate"""
72
56
        state = dirstate.DirState.initialize('dirstate')
413
397
            (('', '', tree.get_root_id()), # common details
414
398
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
415
399
              ('d', '', 0, False, rev_id), # first parent details
416
 
              ('d', '', 0, False, rev_id), # second parent details
 
400
              ('d', '', 0, False, rev_id2), # second parent details
417
401
             ])])
418
402
        state = dirstate.DirState.from_tree(tree, 'dirstate')
419
403
        self.check_state_with_reopen(expected_result, state)
494
478
            (('', '', tree.get_root_id()), # common details
495
479
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
496
480
              ('d', '', 0, False, rev_id), # first parent details
497
 
              ('d', '', 0, False, rev_id), # second parent details
 
481
              ('d', '', 0, False, rev_id2), # second parent details
498
482
             ]),
499
483
            (('', 'a file', 'a-file-id'), # common
500
484
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
821
805
        finally:
822
806
            tree.unlock()
823
807
 
 
808
 
824
809
    def test_set_state_from_inventory_mixed_paths(self):
825
810
        tree1 = self.make_branch_and_tree('tree1')
826
811
        self.build_tree(['tree1/a/', 'tree1/a/b/', 'tree1/a-b/',
867
852
        state = dirstate.DirState.initialize('dirstate')
868
853
        try:
869
854
            # check precondition to be sure the state does change appropriately.
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]
 
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')])]
881
863
            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'))
887
864
            # should work across save too
888
865
            state.save()
889
866
        finally:
907
884
        state._validate()
908
885
        try:
909
886
            state.set_parent_trees([('parent-revid', rt)], ghosts=[])
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')
 
887
            state.set_path_id('', 'foobarbaz')
919
888
            state._validate()
920
889
            # now see that it is what we expected
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]
 
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
                ]
928
900
            state._validate()
929
901
            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'))
940
902
            # should work across save too
941
903
            state.save()
942
904
        finally:
958
920
        finally:
959
921
            state.unlock()
960
922
 
 
923
 
961
924
    def test_set_parent_trees_no_content(self):
962
925
        # set_parent_trees is a slow but important api to support.
963
926
        tree1 = self.make_branch_and_memory_tree('tree1')
968
931
        finally:
969
932
            tree1.unlock()
970
933
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
971
 
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
 
934
        tree2 = MemoryTree.create_on_branch(branch2)
972
935
        tree2.lock_write()
973
936
        try:
974
937
            revid2 = tree2.commit('foo')
1017
980
                [(('', '', root_id), [
1018
981
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
1019
982
                  ('d', '', 0, False, revid1),
1020
 
                  ('d', '', 0, False, revid1)
 
983
                  ('d', '', 0, False, revid2)
1021
984
                  ])],
1022
985
                list(state._iter_entries()))
1023
986
        finally:
1038
1001
        finally:
1039
1002
            tree1.unlock()
1040
1003
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
1041
 
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
 
1004
        tree2 = MemoryTree.create_on_branch(branch2)
1042
1005
        tree2.lock_write()
1043
1006
        try:
1044
1007
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
1051
1014
            (('', '', root_id), [
1052
1015
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
1053
1016
             ('d', '', 0, False, revid1.encode('utf8')),
1054
 
             ('d', '', 0, False, revid1.encode('utf8'))
 
1017
             ('d', '', 0, False, revid2.encode('utf8'))
1055
1018
             ]),
1056
1019
            (('', 'a file', 'file-id'), [
1057
1020
             ('a', '', 0, False, ''),
1103
1066
            state.unlock()
1104
1067
        state = dirstate.DirState.on_file('dirstate')
1105
1068
        state.lock_read()
1106
 
        self.addCleanup(state.unlock)
1107
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
1069
        try:
 
1070
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
1071
        finally:
 
1072
            state.unlock()
1108
1073
 
1109
1074
    def test_add_path_to_unversioned_directory(self):
1110
1075
        """Adding a path to an unversioned directory should error.
1115
1080
        """
1116
1081
        self.build_tree(['unversioned/', 'unversioned/a file'])
1117
1082
        state = dirstate.DirState.initialize('dirstate')
1118
 
        self.addCleanup(state.unlock)
1119
 
        self.assertRaises(errors.NotVersionedError, state.add,
1120
 
                          'unversioned/a file', 'a-file-id', 'file', None, None)
 
1083
        try:
 
1084
            self.assertRaises(errors.NotVersionedError, state.add,
 
1085
                'unversioned/a file', 'a-file-id', 'file', None, None)
 
1086
        finally:
 
1087
            state.unlock()
1121
1088
 
1122
1089
    def test_add_directory_to_root_no_parents_all_data(self):
1123
1090
        # The most trivial addition of a dir is when there are no parents and
1143
1110
            state.unlock()
1144
1111
        state = dirstate.DirState.on_file('dirstate')
1145
1112
        state.lock_read()
1146
 
        self.addCleanup(state.unlock)
1147
1113
        state._validate()
1148
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
1114
        try:
 
1115
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
1116
        finally:
 
1117
            state.unlock()
1149
1118
 
1150
 
    def _test_add_symlink_to_root_no_parents_all_data(self, link_name, target):
 
1119
    def test_add_symlink_to_root_no_parents_all_data(self):
1151
1120
        # The most trivial addition of a symlink when there are no parents and
1152
1121
        # its in the root and all data about the file is supplied
1153
1122
        # bzr doesn't support fake symlinks on windows, yet.
1154
 
        self.requireFeature(tests.SymlinkFeature)
1155
 
        os.symlink(target, link_name)
1156
 
        stat = os.lstat(link_name)
 
1123
        self.requireFeature(SymlinkFeature)
 
1124
        os.symlink('target', 'a link')
 
1125
        stat = os.lstat('a link')
1157
1126
        expected_entries = [
1158
1127
            (('', '', 'TREE_ROOT'), [
1159
1128
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1160
1129
             ]),
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
 
1130
            (('', 'a link', 'a link id'), [
 
1131
             ('l', 'target', 6, False, dirstate.pack_stat(stat)), # current tree
1164
1132
             ]),
1165
1133
            ]
1166
1134
        state = dirstate.DirState.initialize('dirstate')
1167
1135
        try:
1168
 
            state.add(link_name, 'a link id', 'symlink', stat,
1169
 
                      target.encode('UTF-8'))
 
1136
            state.add('a link', 'a link id', 'symlink', stat, 'target')
1170
1137
            # having added it, it should be in the output of iter_entries.
1171
1138
            self.assertEqual(expected_entries, list(state._iter_entries()))
1172
1139
            # saving and reloading should not affect this.
1175
1142
            state.unlock()
1176
1143
        state = dirstate.DirState.on_file('dirstate')
1177
1144
        state.lock_read()
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')
 
1145
        try:
 
1146
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
1147
        finally:
 
1148
            state.unlock()
1188
1149
 
1189
1150
    def test_add_directory_and_child_no_parents_all_data(self):
1190
1151
        # after adding a directory, we should be able to add children to it.
1215
1176
            state.unlock()
1216
1177
        state = dirstate.DirState.on_file('dirstate')
1217
1178
        state.lock_read()
1218
 
        self.addCleanup(state.unlock)
1219
 
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
1179
        try:
 
1180
            self.assertEqual(expected_entries, list(state._iter_entries()))
 
1181
        finally:
 
1182
            state.unlock()
1220
1183
 
1221
1184
    def test_add_tree_reference(self):
1222
1185
        # make a dirstate and add a tree reference
1236
1199
            state.unlock()
1237
1200
        # now check we can read it back
1238
1201
        state.lock_read()
1239
 
        self.addCleanup(state.unlock)
1240
1202
        state._validate()
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)
 
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()
1247
1212
 
1248
1213
    def test_add_forbidden_names(self):
1249
1214
        state = dirstate.DirState.initialize('dirstate')
1253
1218
        self.assertRaises(errors.BzrError,
1254
1219
            state.add, '..', 'ass-id', 'directory', None, None)
1255
1220
 
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
 
 
1288
1221
 
1289
1222
class TestGetLines(TestCaseWithDirState):
1290
1223
 
1619
1552
            list(state._iter_child_entries(1, '')))
1620
1553
 
1621
1554
 
1622
 
class TestDirstateSortOrder(tests.TestCaseWithTransport):
 
1555
class TestDirstateSortOrder(TestCaseWithTransport):
1623
1556
    """Test that DirState adds entries in the right order."""
1624
1557
 
1625
1558
    def test_add_sorting(self):
1741
1674
            st.st_ino, st.st_mode)
1742
1675
 
1743
1676
 
1744
 
class TestPackStat(tests.TestCaseWithTransport):
 
1677
class TestPackStat(TestCaseWithTransport):
1745
1678
 
1746
1679
    def assertPackStat(self, expected, stat_value):
1747
1680
        """Check the packed and serialized form of a stat value."""
2274
2207
        self.assertEqual(exp_dirblocks, state._dirblocks)
2275
2208
 
2276
2209
 
2277
 
class Test_InvEntryToDetails(tests.TestCase):
 
2210
class Test_InvEntryToDetails(TestCaseWithDirState):
2278
2211
 
2279
2212
    def assertDetails(self, expected, inv_entry):
2280
2213
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
2287
2220
        self.assertIsInstance(tree_data, str)
2288
2221
 
2289
2222
    def test_unicode_symlink(self):
2290
 
        inv_entry = inventory.InventoryLink('link-file-id',
2291
 
                                            u'nam\N{Euro Sign}e',
 
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',
2292
2226
                                            'link-parent-id')
2293
2227
        inv_entry.revision = 'link-revision-id'
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):
 
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):
2301
2234
 
2302
2235
    def test_sha1provider_is_an_interface(self):
2303
2236
        p = dirstate.SHA1Provider()