21
21
from bzrlib import (
27
26
from bzrlib.tests import test_graph
28
27
from bzrlib.revision import NULL_REVISION
31
def load_tests(standard_tests, module, loader):
32
"""Parameterize tests for all versions of groupcompress."""
28
from bzrlib.tests.scenarios import load_tests_apply_scenarios
29
from bzrlib.tests import (
34
def caching_scenarios():
34
36
('python', {'module': _known_graph_py, 'do_cache': True}),
38
if compiled_known_graph_feature.available():
39
scenarios.append(('C', {'module': compiled_known_graph_feature.module,
44
def non_caching_scenarios():
37
46
('python-nocache', {'module': _known_graph_py, 'do_cache': False}),
39
suite = loader.suiteClass()
40
if CompiledKnownGraphFeature.available():
41
from bzrlib import _known_graph_pyx
42
scenarios.append(('C', {'module': _known_graph_pyx, 'do_cache': True}))
43
caching_scenarios.append(('C-nocache',
44
{'module': _known_graph_pyx, 'do_cache': False}))
46
# the compiled module isn't available, so we add a failing test
47
class FailWithoutFeature(tests.TestCase):
49
self.requireFeature(CompiledKnownGraphFeature)
50
suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
51
# TestKnownGraphHeads needs to be permutated with and without caching.
52
# All other TestKnownGraph tests only need to be tested across module
53
heads_suite, other_suite = tests.split_suite_by_condition(
54
standard_tests, tests.condition_isinstance(TestKnownGraphHeads))
55
suite = tests.multiply_tests(other_suite, scenarios, suite)
56
suite = tests.multiply_tests(heads_suite, scenarios + caching_scenarios,
61
class _CompiledKnownGraphFeature(tests.Feature):
65
import bzrlib._known_graph_pyx
70
def feature_name(self):
71
return 'bzrlib._known_graph_pyx'
73
CompiledKnownGraphFeature = _CompiledKnownGraphFeature()
48
if compiled_known_graph_feature.available():
50
('C-nocache', {'module': compiled_known_graph_feature.module,
55
load_tests = load_tests_apply_scenarios
58
compiled_known_graph_feature = features.ModuleAvailableFeature(
59
'bzrlib._known_graph_pyx')
100
87
def test_children_ancestry1(self):
101
88
graph = self.make_known_graph(test_graph.ancestry_1)
102
self.assertEqual(['rev1'], graph._nodes[NULL_REVISION].child_keys)
89
self.assertEqual(['rev1'], graph.get_child_keys(NULL_REVISION))
103
90
self.assertEqual(['rev2a', 'rev2b'],
104
sorted(graph._nodes['rev1'].child_keys))
105
self.assertEqual(['rev3'], sorted(graph._nodes['rev2a'].child_keys))
106
self.assertEqual(['rev4'], sorted(graph._nodes['rev3'].child_keys))
107
self.assertEqual(['rev4'], sorted(graph._nodes['rev2b'].child_keys))
91
sorted(graph.get_child_keys('rev1')))
92
self.assertEqual(['rev3'], graph.get_child_keys('rev2a'))
93
self.assertEqual(['rev4'], graph.get_child_keys('rev3'))
94
self.assertEqual(['rev4'], graph.get_child_keys('rev2b'))
95
self.assertRaises(KeyError, graph.get_child_keys, 'not_in_graph')
97
def test_parent_ancestry1(self):
98
graph = self.make_known_graph(test_graph.ancestry_1)
99
self.assertEqual([NULL_REVISION], graph.get_parent_keys('rev1'))
100
self.assertEqual(['rev1'], graph.get_parent_keys('rev2a'))
101
self.assertEqual(['rev1'], graph.get_parent_keys('rev2b'))
102
self.assertEqual(['rev2a'], graph.get_parent_keys('rev3'))
103
self.assertEqual(['rev2b', 'rev3'],
104
sorted(graph.get_parent_keys('rev4')))
105
self.assertRaises(KeyError, graph.get_child_keys, 'not_in_graph')
107
def test_parent_with_ghost(self):
108
graph = self.make_known_graph(test_graph.with_ghost)
109
self.assertEqual(None, graph.get_parent_keys('g'))
109
111
def test_gdfo_ancestry_1(self):
110
112
graph = self.make_known_graph(test_graph.ancestry_1)
139
141
self.assertGDFO(graph, 'a', 5)
140
142
self.assertGDFO(graph, 'c', 5)
144
def test_add_existing_node(self):
145
graph = self.make_known_graph(test_graph.ancestry_1)
146
# Add a node that already exists with identical content
148
self.assertGDFO(graph, 'rev4', 5)
149
graph.add_node('rev4', ['rev3', 'rev2b'])
150
self.assertGDFO(graph, 'rev4', 5)
151
# This also works if we use a tuple rather than a list
152
graph.add_node('rev4', ('rev3', 'rev2b'))
154
def test_add_existing_node_mismatched_parents(self):
155
graph = self.make_known_graph(test_graph.ancestry_1)
156
self.assertRaises(ValueError, graph.add_node, 'rev4',
159
def test_add_node_with_ghost_parent(self):
160
graph = self.make_known_graph(test_graph.ancestry_1)
161
graph.add_node('rev5', ['rev2b', 'revGhost'])
162
self.assertGDFO(graph, 'rev5', 4)
163
self.assertGDFO(graph, 'revGhost', 1)
165
def test_add_new_root(self):
166
graph = self.make_known_graph(test_graph.ancestry_1)
167
graph.add_node('rev5', [])
168
self.assertGDFO(graph, 'rev5', 1)
170
def test_add_with_all_ghost_parents(self):
171
graph = self.make_known_graph(test_graph.ancestry_1)
172
graph.add_node('rev5', ['ghost'])
173
self.assertGDFO(graph, 'rev5', 2)
174
self.assertGDFO(graph, 'ghost', 1)
176
def test_gdfo_after_add_node(self):
177
graph = self.make_known_graph(test_graph.ancestry_1)
178
self.assertEqual([], graph.get_child_keys('rev4'))
179
graph.add_node('rev5', ['rev4'])
180
self.assertEqual(['rev4'], graph.get_parent_keys('rev5'))
181
self.assertEqual(['rev5'], graph.get_child_keys('rev4'))
182
self.assertEqual([], graph.get_child_keys('rev5'))
183
self.assertGDFO(graph, 'rev5', 6)
184
graph.add_node('rev6', ['rev2b'])
185
graph.add_node('rev7', ['rev6'])
186
graph.add_node('rev8', ['rev7', 'rev5'])
187
self.assertGDFO(graph, 'rev5', 6)
188
self.assertGDFO(graph, 'rev6', 4)
189
self.assertGDFO(graph, 'rev7', 5)
190
self.assertGDFO(graph, 'rev8', 7)
192
def test_fill_in_ghost(self):
193
graph = self.make_known_graph(test_graph.with_ghost)
194
# Add in a couple nodes and then fill in the 'ghost' so that it should
195
# cause renumbering of children nodes
196
graph.add_node('x', [])
197
graph.add_node('y', ['x'])
198
graph.add_node('z', ['y'])
199
graph.add_node('g', ['z'])
200
self.assertGDFO(graph, 'f', 2)
201
self.assertGDFO(graph, 'e', 3)
202
self.assertGDFO(graph, 'x', 1)
203
self.assertGDFO(graph, 'y', 2)
204
self.assertGDFO(graph, 'z', 3)
205
self.assertGDFO(graph, 'g', 4)
206
self.assertGDFO(graph, 'b', 4)
207
self.assertGDFO(graph, 'd', 5)
208
self.assertGDFO(graph, 'a', 5)
209
self.assertGDFO(graph, 'c', 6)
143
212
class TestKnownGraphHeads(TestCaseWithKnownGraph):
214
scenarios = caching_scenarios() + non_caching_scenarios()
145
215
do_cache = None # Set by load_tests
147
217
def test_heads_null(self):
851
class TestKnownGraphStableReverseTopoSort(TestCaseWithKnownGraph):
852
"""Test the sort order returned by gc_sort."""
854
def assertSorted(self, expected, parent_map):
855
graph = self.make_known_graph(parent_map)
856
value = graph.gc_sort()
857
if expected != value:
858
self.assertEqualDiff(pprint.pformat(expected),
859
pprint.pformat(value))
861
def test_empty(self):
862
self.assertSorted([], {})
864
def test_single(self):
865
self.assertSorted(['a'], {'a':()})
866
self.assertSorted([('a',)], {('a',):()})
867
self.assertSorted([('F', 'a')], {('F', 'a'):()})
869
def test_linear(self):
870
self.assertSorted(['c', 'b', 'a'], {'a':(), 'b':('a',), 'c':('b',)})
871
self.assertSorted([('c',), ('b',), ('a',)],
872
{('a',):(), ('b',): (('a',),), ('c',): (('b',),)})
873
self.assertSorted([('F', 'c'), ('F', 'b'), ('F', 'a')],
874
{('F', 'a'):(), ('F', 'b'): (('F', 'a'),),
875
('F', 'c'): (('F', 'b'),)})
877
def test_mixed_ancestries(self):
878
# Each prefix should be sorted separately
879
self.assertSorted([('F', 'c'), ('F', 'b'), ('F', 'a'),
880
('G', 'c'), ('G', 'b'), ('G', 'a'),
881
('Q', 'c'), ('Q', 'b'), ('Q', 'a'),
883
{('F', 'a'):(), ('F', 'b'): (('F', 'a'),),
884
('F', 'c'): (('F', 'b'),),
885
('G', 'a'):(), ('G', 'b'): (('G', 'a'),),
886
('G', 'c'): (('G', 'b'),),
887
('Q', 'a'):(), ('Q', 'b'): (('Q', 'a'),),
888
('Q', 'c'): (('Q', 'b'),),
891
def test_stable_sorting(self):
892
# the sort order should be stable even when extra nodes are added
893
self.assertSorted(['b', 'c', 'a'],
894
{'a':(), 'b':('a',), 'c':('a',)})
895
self.assertSorted(['b', 'c', 'd', 'a'],
896
{'a':(), 'b':('a',), 'c':('a',), 'd':('a',)})
897
self.assertSorted(['b', 'c', 'd', 'a'],
898
{'a':(), 'b':('a',), 'c':('a',), 'd':('a',)})
899
self.assertSorted(['Z', 'b', 'c', 'd', 'a'],
900
{'a':(), 'b':('a',), 'c':('a',), 'd':('a',),
902
self.assertSorted(['e', 'b', 'c', 'f', 'Z', 'd', 'a'],
903
{'a':(), 'b':('a',), 'c':('a',), 'd':('a',),
909
def test_skip_ghost(self):
910
self.assertSorted(['b', 'c', 'a'],
911
{'a':(), 'b':('a', 'ghost'), 'c':('a',)})
913
def test_skip_mainline_ghost(self):
914
self.assertSorted(['b', 'c', 'a'],
915
{'a':(), 'b':('ghost', 'a'), 'c':('a',)})