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)
244
248
('f', '', 0, False, null_stat),
245
249
('f', e_sha, e_len, False, revision_id),
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),
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'])
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
1829
1837
(dir, name) tuples, and sorted according to how _bisect
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)
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
1845
expected[dir_name] = sorted(expected_map[k] for k in keys)
1852
expected[path] = sorted(expected_map[k] for k in keys)
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.
1850
1859
self.assertEqual(expected, result)
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'])
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'])
1936
1948
def test_bisect_duplicate_paths(self):
1937
1949
"""When bisecting for a path, handle multiple entries."""
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']],
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'],
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'],
2050
class TestBisectDirblock(TestCase):
2051
"""Test that bisect_dirblock() returns the expected values.
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'.
2058
def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
2059
"""Assert that bisect_split works like bisect_left on the split paths.
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.
2065
All other arguments will be passed along.
2067
bisect_split_idx = dirstate.bisect_dirblock(dirblocks, path,
2069
split_dirblock = (path.split('/'), [])
2070
bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
2072
self.assertEqual(bisect_left_idx, bisect_split_idx,
2073
'bisect_split disagreed. %s != %s'
2075
% (bisect_left_idx, bisect_split_idx, path)
2078
def paths_to_dirblocks(self, paths):
2079
"""Convert a list of paths into dirblock form.
2081
Also, ensure that the paths are in proper sorted order.
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
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)
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')
2104
def test_involved(self):
2105
"""This is where bisect_left diverges slightly."""
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',
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',
2114
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2116
self.assertBisect(dirblocks, split_dirblocks, path)
2118
def test_involved_cached(self):
2119
"""This is where bisect_left diverges slightly."""
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',
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',
2129
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
2131
self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
2134
2067
class TestDirstateValidation(TestCaseWithDirState):
2136
2069
def test_validate_correct_dirstate(self):