/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

  • Committer: Andrew Bennetts
  • Date: 2010-01-12 03:53:21 UTC
  • mfrom: (4948 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4964.
  • Revision ID: andrew.bennetts@canonical.com-20100112035321-hofpz5p10224ryj3
Merge lp:bzr, resolving conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests of the dirstate functionality being built for WorkingTreeFormat4."""
18
18
 
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
 
        TestCaseWithTransport,
34
 
        )
 
31
from bzrlib.tests import test_osutils
35
32
 
36
33
 
37
34
# TODO:
47
44
# set_path_id  setting id when state is in memory modified
48
45
 
49
46
 
50
 
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):
51
58
    """Helper functions for creating DirState objects with various content."""
52
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
        # Save platform specific info and reset it
 
68
        cur_dir_reader = osutils._selected_dir_reader
 
69
 
 
70
        def restore():
 
71
            osutils._selected_dir_reader = cur_dir_reader
 
72
        self.addCleanup(restore)
 
73
 
 
74
        osutils._selected_dir_reader = self._dir_reader_class()
 
75
 
53
76
    def create_empty_dirstate(self):
54
77
        """Return a locked but empty dirstate"""
55
78
        state = dirstate.DirState.initialize('dirstate')
396
419
            (('', '', tree.get_root_id()), # common details
397
420
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
398
421
              ('d', '', 0, False, rev_id), # first parent details
399
 
              ('d', '', 0, False, rev_id2), # second parent details
 
422
              ('d', '', 0, False, rev_id), # second parent details
400
423
             ])])
401
424
        state = dirstate.DirState.from_tree(tree, 'dirstate')
402
425
        self.check_state_with_reopen(expected_result, state)
477
500
            (('', '', tree.get_root_id()), # common details
478
501
             [('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
479
502
              ('d', '', 0, False, rev_id), # first parent details
480
 
              ('d', '', 0, False, rev_id2), # second parent details
 
503
              ('d', '', 0, False, rev_id), # second parent details
481
504
             ]),
482
505
            (('', 'a file', 'a-file-id'), # common
483
506
             [('f', '', 0, False, dirstate.DirState.NULLSTAT), # current
639
662
                state2.unlock()
640
663
        finally:
641
664
            state.unlock()
642
 
        
 
665
 
643
666
        # The file on disk should not be modified.
644
667
        state = dirstate.DirState.on_file('dirstate')
645
668
        state.lock_read()
745
768
        # https://bugs.launchpad.net/bzr/+bug/146176
746
769
        # set_state_from_inventory should preserve the stat and hash value for
747
770
        # workingtree files that are not changed by the inventory.
748
 
       
 
771
 
749
772
        tree = self.make_branch_and_tree('.')
750
773
        # depends on the default format using dirstate...
751
774
        tree.lock_write()
752
775
        try:
753
 
            # make a dirstate with some valid hashcache data 
 
776
            # make a dirstate with some valid hashcache data
754
777
            # file on disk, but that's not needed for this test
755
778
            foo_contents = 'contents of foo'
756
779
            self.build_tree_contents([('foo', foo_contents)])
776
799
                (('', 'foo', 'foo-id',),
777
800
                 [('f', foo_sha, foo_size, False, foo_packed)]),
778
801
                tree._dirstate._get_entry(0, 'foo-id'))
779
 
           
 
802
 
780
803
            # extract the inventory, and add something to it
781
804
            inv = tree._get_inventory()
782
805
            # should see the file we poked in...
804
827
        finally:
805
828
            tree.unlock()
806
829
 
807
 
 
808
830
    def test_set_state_from_inventory_mixed_paths(self):
809
831
        tree1 = self.make_branch_and_tree('tree1')
810
832
        self.build_tree(['tree1/a/', 'tree1/a/b/', 'tree1/a-b/',
919
941
        finally:
920
942
            state.unlock()
921
943
 
922
 
 
923
944
    def test_set_parent_trees_no_content(self):
924
945
        # set_parent_trees is a slow but important api to support.
925
946
        tree1 = self.make_branch_and_memory_tree('tree1')
930
951
        finally:
931
952
            tree1.unlock()
932
953
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
933
 
        tree2 = MemoryTree.create_on_branch(branch2)
 
954
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
934
955
        tree2.lock_write()
935
956
        try:
936
957
            revid2 = tree2.commit('foo')
979
1000
                [(('', '', root_id), [
980
1001
                  ('d', '', 0, False, dirstate.DirState.NULLSTAT),
981
1002
                  ('d', '', 0, False, revid1),
982
 
                  ('d', '', 0, False, revid2)
 
1003
                  ('d', '', 0, False, revid1)
983
1004
                  ])],
984
1005
                list(state._iter_entries()))
985
1006
        finally:
1000
1021
        finally:
1001
1022
            tree1.unlock()
1002
1023
        branch2 = tree1.branch.bzrdir.clone('tree2').open_branch()
1003
 
        tree2 = MemoryTree.create_on_branch(branch2)
 
1024
        tree2 = memorytree.MemoryTree.create_on_branch(branch2)
1004
1025
        tree2.lock_write()
1005
1026
        try:
1006
1027
            tree2.put_file_bytes_non_atomic('file-id', 'new file-content')
1013
1034
            (('', '', root_id), [
1014
1035
             ('d', '', 0, False, dirstate.DirState.NULLSTAT),
1015
1036
             ('d', '', 0, False, revid1.encode('utf8')),
1016
 
             ('d', '', 0, False, revid2.encode('utf8'))
 
1037
             ('d', '', 0, False, revid1.encode('utf8'))
1017
1038
             ]),
1018
1039
            (('', 'a file', 'file-id'), [
1019
1040
             ('a', '', 0, False, ''),
1065
1086
            state.unlock()
1066
1087
        state = dirstate.DirState.on_file('dirstate')
1067
1088
        state.lock_read()
1068
 
        try:
1069
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1070
 
        finally:
1071
 
            state.unlock()
 
1089
        self.addCleanup(state.unlock)
 
1090
        self.assertEqual(expected_entries, list(state._iter_entries()))
1072
1091
 
1073
1092
    def test_add_path_to_unversioned_directory(self):
1074
1093
        """Adding a path to an unversioned directory should error.
1079
1098
        """
1080
1099
        self.build_tree(['unversioned/', 'unversioned/a file'])
1081
1100
        state = dirstate.DirState.initialize('dirstate')
1082
 
        try:
1083
 
            self.assertRaises(errors.NotVersionedError, state.add,
1084
 
                'unversioned/a file', 'a-file-id', 'file', None, None)
1085
 
        finally:
1086
 
            state.unlock()
 
1101
        self.addCleanup(state.unlock)
 
1102
        self.assertRaises(errors.NotVersionedError, state.add,
 
1103
                          'unversioned/a file', 'a-file-id', 'file', None, None)
1087
1104
 
1088
1105
    def test_add_directory_to_root_no_parents_all_data(self):
1089
1106
        # The most trivial addition of a dir is when there are no parents and
1109
1126
            state.unlock()
1110
1127
        state = dirstate.DirState.on_file('dirstate')
1111
1128
        state.lock_read()
 
1129
        self.addCleanup(state.unlock)
1112
1130
        state._validate()
1113
 
        try:
1114
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1115
 
        finally:
1116
 
            state.unlock()
 
1131
        self.assertEqual(expected_entries, list(state._iter_entries()))
1117
1132
 
1118
 
    def test_add_symlink_to_root_no_parents_all_data(self):
 
1133
    def _test_add_symlink_to_root_no_parents_all_data(self, link_name, target):
1119
1134
        # The most trivial addition of a symlink when there are no parents and
1120
1135
        # its in the root and all data about the file is supplied
1121
1136
        # bzr doesn't support fake symlinks on windows, yet.
1122
 
        self.requireFeature(SymlinkFeature)
1123
 
        os.symlink('target', 'a link')
1124
 
        stat = os.lstat('a link')
 
1137
        self.requireFeature(tests.SymlinkFeature)
 
1138
        os.symlink(target, link_name)
 
1139
        stat = os.lstat(link_name)
1125
1140
        expected_entries = [
1126
1141
            (('', '', 'TREE_ROOT'), [
1127
1142
             ('d', '', 0, False, dirstate.DirState.NULLSTAT), # current tree
1128
1143
             ]),
1129
 
            (('', 'a link', 'a link id'), [
1130
 
             ('l', 'target', 6, False, dirstate.pack_stat(stat)), # current tree
 
1144
            (('', link_name.encode('UTF-8'), 'a link id'), [
 
1145
             ('l', target.encode('UTF-8'), stat[6],
 
1146
              False, dirstate.pack_stat(stat)), # current tree
1131
1147
             ]),
1132
1148
            ]
1133
1149
        state = dirstate.DirState.initialize('dirstate')
1134
1150
        try:
1135
 
            state.add('a link', 'a link id', 'symlink', stat, 'target')
 
1151
            state.add(link_name, 'a link id', 'symlink', stat,
 
1152
                      target.encode('UTF-8'))
1136
1153
            # having added it, it should be in the output of iter_entries.
1137
1154
            self.assertEqual(expected_entries, list(state._iter_entries()))
1138
1155
            # saving and reloading should not affect this.
1141
1158
            state.unlock()
1142
1159
        state = dirstate.DirState.on_file('dirstate')
1143
1160
        state.lock_read()
1144
 
        try:
1145
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1146
 
        finally:
1147
 
            state.unlock()
 
1161
        self.addCleanup(state.unlock)
 
1162
        self.assertEqual(expected_entries, list(state._iter_entries()))
 
1163
 
 
1164
    def test_add_symlink_to_root_no_parents_all_data(self):
 
1165
        self._test_add_symlink_to_root_no_parents_all_data('a link', 'target')
 
1166
 
 
1167
    def test_add_symlink_unicode_to_root_no_parents_all_data(self):
 
1168
        self.requireFeature(tests.UnicodeFilenameFeature)
 
1169
        self._test_add_symlink_to_root_no_parents_all_data(
 
1170
            u'\N{Euro Sign}link', u'targ\N{Euro Sign}et')
1148
1171
 
1149
1172
    def test_add_directory_and_child_no_parents_all_data(self):
1150
1173
        # after adding a directory, we should be able to add children to it.
1175
1198
            state.unlock()
1176
1199
        state = dirstate.DirState.on_file('dirstate')
1177
1200
        state.lock_read()
1178
 
        try:
1179
 
            self.assertEqual(expected_entries, list(state._iter_entries()))
1180
 
        finally:
1181
 
            state.unlock()
 
1201
        self.addCleanup(state.unlock)
 
1202
        self.assertEqual(expected_entries, list(state._iter_entries()))
1182
1203
 
1183
1204
    def test_add_tree_reference(self):
1184
1205
        # make a dirstate and add a tree reference
1198
1219
            state.unlock()
1199
1220
        # now check we can read it back
1200
1221
        state.lock_read()
 
1222
        self.addCleanup(state.unlock)
1201
1223
        state._validate()
1202
 
        try:
1203
 
            entry2 = state._get_entry(0, 'subdir-id', 'subdir')
1204
 
            self.assertEqual(entry, entry2)
1205
 
            self.assertEqual(entry, expected_entry)
1206
 
            # and lookup by id should work too
1207
 
            entry2 = state._get_entry(0, fileid_utf8='subdir-id')
1208
 
            self.assertEqual(entry, expected_entry)
1209
 
        finally:
1210
 
            state.unlock()
 
1224
        entry2 = state._get_entry(0, 'subdir-id', 'subdir')
 
1225
        self.assertEqual(entry, entry2)
 
1226
        self.assertEqual(entry, expected_entry)
 
1227
        # and lookup by id should work too
 
1228
        entry2 = state._get_entry(0, fileid_utf8='subdir-id')
 
1229
        self.assertEqual(entry, expected_entry)
1211
1230
 
1212
1231
    def test_add_forbidden_names(self):
1213
1232
        state = dirstate.DirState.initialize('dirstate')
1217
1236
        self.assertRaises(errors.BzrError,
1218
1237
            state.add, '..', 'ass-id', 'directory', None, None)
1219
1238
 
 
1239
    def test_set_state_with_rename_b_a_bug_395556(self):
 
1240
        # bug 395556 uncovered a bug where the dirstate ends up with a false
 
1241
        # relocation record - in a tree with no parents there should be no
 
1242
        # absent or relocated records. This then leads to further corruption
 
1243
        # when a commit occurs, as the incorrect relocation gathers an
 
1244
        # incorrect absent in tree 1, and future changes go to pot.
 
1245
        tree1 = self.make_branch_and_tree('tree1')
 
1246
        self.build_tree(['tree1/b'])
 
1247
        tree1.lock_write()
 
1248
        try:
 
1249
            tree1.add(['b'], ['b-id'])
 
1250
            root_id = tree1.get_root_id()
 
1251
            inv = tree1.inventory
 
1252
            state = dirstate.DirState.initialize('dirstate')
 
1253
            try:
 
1254
                # Set the initial state with 'b'
 
1255
                state.set_state_from_inventory(inv)
 
1256
                inv.rename('b-id', root_id, 'a')
 
1257
                # Set the new state with 'a', which currently corrupts.
 
1258
                state.set_state_from_inventory(inv)
 
1259
                expected_result1 = [('', '', root_id, 'd'),
 
1260
                                    ('', 'a', 'b-id', 'f'),
 
1261
                                   ]
 
1262
                values = []
 
1263
                for entry in state._iter_entries():
 
1264
                    values.append(entry[0] + entry[1][0][:1])
 
1265
                self.assertEqual(expected_result1, values)
 
1266
            finally:
 
1267
                state.unlock()
 
1268
        finally:
 
1269
            tree1.unlock()
 
1270
 
1220
1271
 
1221
1272
class TestGetLines(TestCaseWithDirState):
1222
1273
 
1455
1506
        There is one parent tree, which has the same shape with the following variations:
1456
1507
        b/g in the parent is gone.
1457
1508
        b/h in the parent has a different id
1458
 
        b/i is new in the parent 
 
1509
        b/i is new in the parent
1459
1510
        c is renamed to b/j in the parent
1460
1511
 
1461
1512
        :return: The dirstate, still write-locked.
1551
1602
            list(state._iter_child_entries(1, '')))
1552
1603
 
1553
1604
 
1554
 
class TestDirstateSortOrder(TestCaseWithTransport):
 
1605
class TestDirstateSortOrder(tests.TestCaseWithTransport):
1555
1606
    """Test that DirState adds entries in the right order."""
1556
1607
 
1557
1608
    def test_add_sorting(self):
1616
1667
class InstrumentedDirState(dirstate.DirState):
1617
1668
    """An DirState with instrumented sha1 functionality."""
1618
1669
 
1619
 
    def __init__(self, path):
1620
 
        super(InstrumentedDirState, self).__init__(path)
 
1670
    def __init__(self, path, sha1_provider):
 
1671
        super(InstrumentedDirState, self).__init__(path, sha1_provider)
1621
1672
        self._time_offset = 0
1622
1673
        self._log = []
1623
1674
        # member is dynamically set in DirState.__init__ to turn on trace
 
1675
        self._sha1_provider = sha1_provider
1624
1676
        self._sha1_file = self._sha1_file_and_log
1625
1677
 
1626
1678
    def _sha_cutoff_time(self):
1629
1681
 
1630
1682
    def _sha1_file_and_log(self, abspath):
1631
1683
        self._log.append(('sha1', abspath))
1632
 
        return osutils.sha_file_by_name(abspath)
 
1684
        return self._sha1_provider.sha1(abspath)
1633
1685
 
1634
1686
    def _read_link(self, abspath, old_link):
1635
1687
        self._log.append(('read_link', abspath, old_link))
1666
1718
        self.st_ino = ino
1667
1719
        self.st_mode = mode
1668
1720
 
1669
 
 
1670
 
class TestPackStat(TestCaseWithTransport):
 
1721
    @staticmethod
 
1722
    def from_stat(st):
 
1723
        return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
 
1724
            st.st_ino, st.st_mode)
 
1725
 
 
1726
 
 
1727
class TestPackStat(tests.TestCaseWithTransport):
1671
1728
 
1672
1729
    def assertPackStat(self, expected, stat_value):
1673
1730
        """Check the packed and serialized form of a stat value."""
2200
2257
        self.assertEqual(exp_dirblocks, state._dirblocks)
2201
2258
 
2202
2259
 
2203
 
class Test_InvEntryToDetails(TestCaseWithDirState):
 
2260
class Test_InvEntryToDetails(tests.TestCase):
2204
2261
 
2205
2262
    def assertDetails(self, expected, inv_entry):
2206
2263
        details = dirstate.DirState._inv_entry_to_details(inv_entry)
2213
2270
        self.assertIsInstance(tree_data, str)
2214
2271
 
2215
2272
    def test_unicode_symlink(self):
2216
 
        # In general, the code base doesn't support a target that contains
2217
 
        # non-ascii characters. So we just assert tha 
2218
 
        inv_entry = inventory.InventoryLink('link-file-id', 'name',
 
2273
        inv_entry = inventory.InventoryLink('link-file-id',
 
2274
                                            u'nam\N{Euro Sign}e',
2219
2275
                                            'link-parent-id')
2220
2276
        inv_entry.revision = 'link-revision-id'
2221
 
        inv_entry.symlink_target = u'link-target'
2222
 
        details = self.assertDetails(('l', 'link-target', 0, False,
2223
 
                                      'link-revision-id'), inv_entry)
 
2277
        target = u'link-targ\N{Euro Sign}t'
 
2278
        inv_entry.symlink_target = target
 
2279
        self.assertDetails(('l', target.encode('UTF-8'), 0, False,
 
2280
                            'link-revision-id'), inv_entry)
 
2281
 
 
2282
 
 
2283
class TestSHA1Provider(tests.TestCaseInTempDir):
 
2284
 
 
2285
    def test_sha1provider_is_an_interface(self):
 
2286
        p = dirstate.SHA1Provider()
 
2287
        self.assertRaises(NotImplementedError, p.sha1, "foo")
 
2288
        self.assertRaises(NotImplementedError, p.stat_and_sha1, "foo")
 
2289
 
 
2290
    def test_defaultsha1provider_sha1(self):
 
2291
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
 
2292
        self.build_tree_contents([('foo', text)])
 
2293
        expected_sha = osutils.sha_string(text)
 
2294
        p = dirstate.DefaultSHA1Provider()
 
2295
        self.assertEqual(expected_sha, p.sha1('foo'))
 
2296
 
 
2297
    def test_defaultsha1provider_stat_and_sha1(self):
 
2298
        text = 'test\r\nwith\nall\rpossible line endings\r\n'
 
2299
        self.build_tree_contents([('foo', text)])
 
2300
        expected_sha = osutils.sha_string(text)
 
2301
        p = dirstate.DefaultSHA1Provider()
 
2302
        statvalue, sha1 = p.stat_and_sha1('foo')
 
2303
        self.assertTrue(len(statvalue) >= 10)
 
2304
        self.assertEqual(len(text), statvalue.st_size)
 
2305
        self.assertEqual(expected_sha, sha1)