~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_dirstate.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
189
189
              c
190
190
              d/
191
191
                e
 
192
            b-c
192
193
            f
193
194
        """
194
195
        tree = self.make_branch_and_tree('tree')
195
 
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'f']
196
 
        file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id']
 
196
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'b-c', 'f']
 
197
        file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'b-c-id', 'f-id']
197
198
        self.build_tree(['tree/' + p for p in paths])
198
199
        tree.set_root_id('TREE_ROOT')
199
200
        tree.add([p.rstrip('/') for p in paths], file_ids)
214
215
        e_text = t.get_bytes('b/d/e')
215
216
        e_sha = osutils.sha_string(e_text)
216
217
        e_len = len(e_text)
 
218
        b_c_text = t.get_bytes('b-c')
 
219
        b_c_sha = osutils.sha_string(b_c_text)
 
220
        b_c_len = len(b_c_text)
217
221
        # f_packed_stat = dirstate.pack_stat(os.stat('tree/f'))
218
222
        f_text = t.get_bytes('f')
219
223
        f_sha = osutils.sha_string(f_text)
244
248
                      ('f', '', 0, False, null_stat),
245
249
                      ('f', e_sha, e_len, False, revision_id),
246
250
                     ]),
 
251
            'b-c':(('', 'b-c', 'b-c-id'), [
 
252
                      ('f', '', 0, False, null_stat),
 
253
                      ('f', b_c_sha, b_c_len, False, revision_id),
 
254
                     ]),
247
255
            'f':(('', 'f', 'f-id'), [
248
256
                  ('f', '', 0, False, null_stat),
249
257
                  ('f', f_sha, f_len, False, revision_id),
276
284
        tree, state, expected = self.create_basic_dirstate()
277
285
        # Now we will just remove and add every file so we get an extra entry
278
286
        # per entry. Unversion in reverse order so we handle subdirs
279
 
        tree.unversion(['f-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
280
 
        tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f'],
281
 
                 ['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'f-id2'])
 
287
        tree.unversion(['f-id', 'b-c-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
 
288
        tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f'],
 
289
                 ['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'b-c-id2', 'f-id2'])
282
290
 
283
291
        # Update the expected dictionary.
284
 
        for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f']:
 
292
        for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'b-c', 'f']:
285
293
            orig = expected[path]
286
294
            path2 = path + '2'
287
295
            # This record was deleted in the current tree
344
352
            state.lock_read()
345
353
        return tree, state, expected
346
354
 
 
355
 
347
356
class TestTreeToDirState(TestCaseWithDirState):
348
357
 
349
358
    def test_empty_to_dirstate(self):
1818
1827
class TestBisect(TestCaseWithDirState):
1819
1828
    """Test the ability to bisect into the disk format."""
1820
1829
 
1821
 
 
1822
1830
    def assertBisect(self, expected_map, map_keys, state, paths):
1823
1831
        """Assert that bisecting for paths returns the right result.
1824
1832
 
1829
1837
                      (dir, name) tuples, and sorted according to how _bisect
1830
1838
                      requires.
1831
1839
        """
1832
 
        dir_names = sorted(osutils.split(p) for p in paths)
1833
 
        result = state._bisect(dir_names)
 
1840
        result = state._bisect(paths)
1834
1841
        # For now, results are just returned in whatever order we read them.
1835
1842
        # We could sort by (dir, name, file_id) or something like that, but in
1836
1843
        # the end it would still be fairly arbitrary, and we don't want the
1837
1844
        # extra overhead if we can avoid it. So sort everything to make sure
1838
1845
        # equality is true
1839
 
        assert len(map_keys) == len(dir_names)
 
1846
        assert len(map_keys) == len(paths)
1840
1847
        expected = {}
1841
 
        for dir_name, keys in zip(dir_names, map_keys):
 
1848
        for path, keys in zip(paths, map_keys):
1842
1849
            if keys is None:
1843
1850
                # This should not be present in the output
1844
1851
                continue
1845
 
            expected[dir_name] = sorted(expected_map[k] for k in keys)
 
1852
            expected[path] = sorted(expected_map[k] for k in keys)
1846
1853
 
1847
 
        for dir_name in result:
1848
 
            result[dir_name].sort()
 
1854
        # The returned values are just arranged randomly based on when they
 
1855
        # were read, for testing, make sure it is properly sorted.
 
1856
        for path in result:
 
1857
            result[path].sort()
1849
1858
 
1850
1859
        self.assertEqual(expected, result)
1851
1860
 
1888
1897
            dir_name_id, trees_info = entry
1889
1898
            expected[dir_name_id] = trees_info
1890
1899
 
1891
 
        dir_names = sorted(osutils.split(p) for p in paths)
1892
 
        result = state._bisect_recursive(dir_names)
 
1900
        result = state._bisect_recursive(paths)
1893
1901
 
1894
1902
        self.assertEqual(expected, result)
1895
1903
 
1904
1912
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1905
1913
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1906
1914
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
 
1915
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
1907
1916
        self.assertBisect(expected, [['f']], state, ['f'])
1908
1917
 
1909
1918
    def test_bisect_multi(self):
1912
1921
        # Bisect should be capable of finding multiple entries at the same time
1913
1922
        self.assertBisect(expected, [['a'], ['b'], ['f']],
1914
1923
                          state, ['a', 'b', 'f'])
1915
 
        # ('', 'f') sorts before the others
1916
1924
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
1917
 
                          state, ['b/d', 'b/d/e', 'f'])
 
1925
                          state, ['f', 'b/d', 'b/d/e'])
 
1926
        self.assertBisect(expected, [['b'], ['b-c'], ['b/c']],
 
1927
                          state, ['b', 'b-c', 'b/c'])
1918
1928
 
1919
1929
    def test_bisect_one_page(self):
1920
1930
        """Test bisect when there is only 1 page to read"""
1926
1936
        self.assertBisect(expected,[['b/c']], state, ['b/c'])
1927
1937
        self.assertBisect(expected,[['b/d']], state, ['b/d'])
1928
1938
        self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
 
1939
        self.assertBisect(expected,[['b-c']], state, ['b-c'])
1929
1940
        self.assertBisect(expected,[['f']], state, ['f'])
1930
1941
        self.assertBisect(expected,[['a'], ['b'], ['f']],
1931
1942
                          state, ['a', 'b', 'f'])
1932
 
        # ('', 'f') sorts before the others
1933
 
        self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
 
1943
        self.assertBisect(expected, [['b/d'], ['b/d/e'], ['f']],
1934
1944
                          state, ['b/d', 'b/d/e', 'f'])
 
1945
        self.assertBisect(expected, [['b'], ['b/c'], ['b-c']],
 
1946
                          state, ['b', 'b/c', 'b-c'])
1935
1947
 
1936
1948
    def test_bisect_duplicate_paths(self):
1937
1949
        """When bisecting for a path, handle multiple entries."""
1945
1957
        self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
1946
1958
        self.assertBisect(expected, [['b/d/e', 'b/d/e2']],
1947
1959
                          state, ['b/d/e'])
 
1960
        self.assertBisect(expected, [['b-c', 'b-c2']], state, ['b-c'])
1948
1961
        self.assertBisect(expected, [['f', 'f2']], state, ['f'])
1949
1962
 
1950
1963
    def test_bisect_page_size_too_small(self):
1957
1970
        self.assertBisect(expected, [['b/c']], state, ['b/c'])
1958
1971
        self.assertBisect(expected, [['b/d']], state, ['b/d'])
1959
1972
        self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
 
1973
        self.assertBisect(expected, [['b-c']], state, ['b-c'])
1960
1974
        self.assertBisect(expected, [['f']], state, ['f'])
1961
1975
 
1962
1976
    def test_bisect_missing(self):
1965
1979
        self.assertBisect(expected, [None], state, ['foo'])
1966
1980
        self.assertBisect(expected, [None], state, ['b/foo'])
1967
1981
        self.assertBisect(expected, [None], state, ['bar/foo'])
 
1982
        self.assertBisect(expected, [None], state, ['b-c/foo'])
1968
1983
 
1969
1984
        self.assertBisect(expected, [['a'], None, ['b/d']],
1970
1985
                          state, ['a', 'foo', 'b/d'])
1986
2001
    def test_bisect_dirblocks(self):
1987
2002
        tree, state, expected = self.create_duplicated_dirstate()
1988
2003
        self.assertBisectDirBlocks(expected,
1989
 
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2']], state, [''])
 
2004
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2']],
 
2005
            state, [''])
1990
2006
        self.assertBisectDirBlocks(expected,
1991
2007
            [['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
1992
2008
        self.assertBisectDirBlocks(expected,
1993
2009
            [['b/d/e', 'b/d/e2']], state, ['b/d'])
1994
2010
        self.assertBisectDirBlocks(expected,
1995
 
            [['', 'a', 'a2', 'b', 'b2', 'f', 'f2'],
 
2011
            [['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2'],
1996
2012
             ['b/c', 'b/c2', 'b/d', 'b/d2'],
1997
2013
             ['b/d/e', 'b/d/e2'],
1998
2014
            ], state, ['', 'b', 'b/d'])
2013
2029
        self.assertBisectRecursive(expected, ['a'], state, ['a'])
2014
2030
        self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
2015
2031
        self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
 
2032
        self.assertBisectRecursive(expected, ['b-c'], state, ['b-c'])
2016
2033
        self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2017
2034
                                   state, ['b/d'])
2018
2035
        self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
2019
2036
                                   state, ['b'])
2020
 
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'f', 'b/c',
 
2037
        self.assertBisectRecursive(expected, ['', 'a', 'b', 'b-c', 'f', 'b/c',
2021
2038
                                              'b/d', 'b/d/e'],
2022
2039
                                   state, [''])
2023
2040
 
2047
2064
                                   state, ['b'])
2048
2065
 
2049
2066
 
2050
 
class TestBisectDirblock(TestCase):
2051
 
    """Test that bisect_dirblock() returns the expected values.
2052
 
 
2053
 
    bisect_dirblock is intended to work like bisect.bisect_left() except it
2054
 
    knows it is working on dirblocks and that dirblocks are sorted by ('path',
2055
 
    'to', 'foo') chunks rather than by raw 'path/to/foo'.
2056
 
    """
2057
 
 
2058
 
    def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
2059
 
        """Assert that bisect_split works like bisect_left on the split paths.
2060
 
 
2061
 
        :param dirblocks: A list of (path, [info]) pairs.
2062
 
        :param split_dirblocks: A list of ((split, path), [info]) pairs.
2063
 
        :param path: The path we are indexing.
2064
 
 
2065
 
        All other arguments will be passed along.
2066
 
        """
2067
 
        bisect_split_idx = dirstate.bisect_dirblock(dirblocks, path,
2068
 
                                                 *args, **kwargs)
2069
 
        split_dirblock = (path.split('/'), [])
2070
 
        bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
2071
 
                                             *args)
2072
 
        self.assertEqual(bisect_left_idx, bisect_split_idx,
2073
 
                         'bisect_split disagreed. %s != %s'
2074
 
                         ' for key %s'
2075
 
                         % (bisect_left_idx, bisect_split_idx, path)
2076
 
                         )
2077
 
 
2078
 
    def paths_to_dirblocks(self, paths):
2079
 
        """Convert a list of paths into dirblock form.
2080
 
 
2081
 
        Also, ensure that the paths are in proper sorted order.
2082
 
        """
2083
 
        dirblocks = [(path, []) for path in paths]
2084
 
        split_dirblocks = [(path.split('/'), []) for path in paths]
2085
 
        self.assertEqual(sorted(split_dirblocks), split_dirblocks)
2086
 
        return dirblocks, split_dirblocks
2087
 
 
2088
 
    def test_simple(self):
2089
 
        """In the simple case it works just like bisect_left"""
2090
 
        paths = ['', 'a', 'b', 'c', 'd']
2091
 
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2092
 
        for path in paths:
2093
 
            self.assertBisect(dirblocks, split_dirblocks, path)
2094
 
        self.assertBisect(dirblocks, split_dirblocks, '_')
2095
 
        self.assertBisect(dirblocks, split_dirblocks, 'aa')
2096
 
        self.assertBisect(dirblocks, split_dirblocks, 'bb')
2097
 
        self.assertBisect(dirblocks, split_dirblocks, 'cc')
2098
 
        self.assertBisect(dirblocks, split_dirblocks, 'dd')
2099
 
        self.assertBisect(dirblocks, split_dirblocks, 'a/a')
2100
 
        self.assertBisect(dirblocks, split_dirblocks, 'b/b')
2101
 
        self.assertBisect(dirblocks, split_dirblocks, 'c/c')
2102
 
        self.assertBisect(dirblocks, split_dirblocks, 'd/d')
2103
 
 
2104
 
    def test_involved(self):
2105
 
        """This is where bisect_left diverges slightly."""
2106
 
        paths = ['', 'a',
2107
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2108
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2109
 
                 'a-a', 'a-z',
2110
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2111
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2112
 
                 'z-a', 'z-z',
2113
 
                ]
2114
 
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2115
 
        for path in paths:
2116
 
            self.assertBisect(dirblocks, split_dirblocks, path)
2117
 
 
2118
 
    def test_involved_cached(self):
2119
 
        """This is where bisect_left diverges slightly."""
2120
 
        paths = ['', 'a',
2121
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
2122
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
2123
 
                 'a-a', 'a-z',
2124
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
2125
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
2126
 
                 'z-a', 'z-z',
2127
 
                ]
2128
 
        cache = {}
2129
 
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2130
 
        for path in paths:
2131
 
            self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
2132
 
 
2133
 
 
2134
2067
class TestDirstateValidation(TestCaseWithDirState):
2135
2068
 
2136
2069
    def test_validate_correct_dirstate(self):
2186
2119
            state._validate)
2187
2120
        self.assertContainsRe(str(e),
2188
2121
            'file a-id is absent in row')
 
2122