160
double_shortcut = {b'a':[NULL_REVISION], b'b':[b'a'], b'c':[b'b'],
161
b'd':[b'c'], b'e':[b'c'], b'f':[b'a', b'd'],
160
double_shortcut = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'],
161
b'd': [b'c'], b'e': [b'c'], b'f': [b'a', b'd'],
164
164
# Complex shortcut
165
165
# This has a failure mode in that a shortcut will find some nodes in common,
192
complex_shortcut = {b'a':[NULL_REVISION], b'b':[b'a'], b'c':[b'b'], b'd':[b'c'],
193
b'e':[b'd'], b'f':[b'd'], b'g':[b'f'], b'h':[b'f'],
194
b'i':[b'e', b'g'], b'j':[b'g'], b'k':[b'j'],
195
b'l':[b'k'], b'm':[b'i', b'l'], b'n':[b'l', b'h']}
192
complex_shortcut = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'], b'd': [b'c'],
193
b'e': [b'd'], b'f': [b'd'], b'g': [b'f'], b'h': [b'f'],
194
b'i': [b'e', b'g'], b'j': [b'g'], b'k': [b'j'],
195
b'l': [b'k'], b'm': [b'i', b'l'], b'n': [b'l', b'h']}
235
235
complex_shortcut2 = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'], b'd': [b'c'],
236
b'e': [b'd'], b'f': [b'e'], b'g': [b'f'], b'h': [b'd'], b'i': [b'g'],
237
b'j': [b'h'], b'k': [b'h', b'i'], b'l': [b'k'], b'm': [b'l'], b'n': [b'm'],
238
b'o': [b'n'], b'p': [b'o'], b'q': [b'p'], b'r': [b'q'], b's': [b'r'],
239
b't': [b'i', b's'], b'u': [b's', b'j'],
236
b'e': [b'd'], b'f': [b'e'], b'g': [b'f'], b'h': [b'd'], b'i': [b'g'],
237
b'j': [b'h'], b'k': [b'h', b'i'], b'l': [b'k'], b'm': [b'l'], b'n': [b'm'],
238
b'o': [b'n'], b'p': [b'o'], b'q': [b'p'], b'r': [b'q'], b's': [b'r'],
239
b't': [b'i', b's'], b'u': [b's', b'j'],
242
242
# Graph where different walkers will race to find the common and uncommon
290
290
# k-n exists so that the second pass still has nodes that are worth searching,
291
291
# rather than instantly cancelling the extra walker.
293
racing_shortcuts = {b'a':[NULL_REVISION], b'b':[b'a'], b'c':[b'b'], b'd':[b'c'],
294
b'e':[b'd'], b'f':[b'e'], b'g':[b'f'], b'h':[b'g'], b'i':[b'h', b'o'], b'j':[b'i', b'y'],
295
b'k':[b'd'], b'l':[b'k'], b'm':[b'l'], b'n':[b'm'], b'o':[b'n', b'g'], b'p':[b'f'],
296
b'q':[b'p', b'm'], b'r':[b'o'], b's':[b'r'], b't':[b's'], b'u':[b't'], b'v':[b'u'],
297
b'w':[b'v'], b'x':[b'w'], b'y':[b'x'], b'z':[b'x', b'q']}
293
racing_shortcuts = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'], b'd': [b'c'],
294
b'e': [b'd'], b'f': [b'e'], b'g': [b'f'], b'h': [b'g'], b'i': [b'h', b'o'], b'j': [b'i', b'y'],
295
b'k': [b'd'], b'l': [b'k'], b'm': [b'l'], b'n': [b'm'], b'o': [b'n', b'g'], b'p': [b'f'],
296
b'q': [b'p', b'm'], b'r': [b'o'], b's': [b'r'], b't': [b's'], b'u': [b't'], b'v': [b'u'],
297
b'w': [b'v'], b'x': [b'w'], b'y': [b'x'], b'z': [b'x', b'q']}
300
300
# A graph with multiple nodes unique to one side.
339
multiple_interesting_unique = {b'a':[NULL_REVISION], b'b':[b'a'], b'c':[b'b'],
340
b'd':[b'c'], b'e':[b'd'], b'f':[b'd'], b'g':[b'e'], b'h':[b'e'], b'i':[b'f'],
341
b'j':[b'g'], b'k':[b'g'], b'l':[b'h'], b'm':[b'i'], b'n':[b'k', b'l'],
342
b'o':[b'm'], b'p':[b'm', b'l'], b'q':[b'n', b'o'], b'r':[b'q'], b's':[b'r'],
343
b't':[b's'], b'u':[b't'], b'v':[b'u'], b'w':[b'v'], b'x':[b'w'],
344
b'y':[b'j', b'x'], b'z':[b'x', b'p']}
339
multiple_interesting_unique = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'],
340
b'd': [b'c'], b'e': [b'd'], b'f': [b'd'], b'g': [b'e'], b'h': [b'e'], b'i': [b'f'],
341
b'j': [b'g'], b'k': [b'g'], b'l': [b'h'], b'm': [b'i'], b'n': [b'k', b'l'],
342
b'o': [b'm'], b'p': [b'm', b'l'], b'q': [b'n', b'o'], b'r': [b'q'], b's': [b'r'],
343
b't': [b's'], b'u': [b't'], b'v': [b'u'], b'w': [b'v'], b'x': [b'w'],
344
b'y': [b'j', b'x'], b'z': [b'x', b'p']}
347
347
# Shortcut with extra root
395
with_ghost = {b'a': [b'b'], b'c': [b'b', b'd'], b'b':[b'e'], b'd':[b'e', b'g'],
396
b'e': [b'f'], b'f':[NULL_REVISION], NULL_REVISION:()}
395
with_ghost = {b'a': [b'b'], b'c': [b'b', b'd'], b'b': [b'e'], b'd': [b'e', b'g'],
396
b'e': [b'f'], b'f': [NULL_REVISION], NULL_REVISION: ()}
398
398
# A graph that shows we can shortcut finding revnos when reaching them from the
418
with_tail = {b'a':[NULL_REVISION], b'b':[b'a'], b'c':[b'b'], b'd':[b'c'], b'e':[b'd'],
419
b'f':[b'e'], b'g':[b'e'], b'h':[b'f'], b'i':[b'h']}
418
with_tail = {b'a': [NULL_REVISION], b'b': [b'a'], b'c': [b'b'], b'd': [b'c'], b'e': [b'd'],
419
b'f': [b'e'], b'g': [b'e'], b'h': [b'f'], b'i': [b'h']}
422
422
class InstrumentedParentsProvider(object):
591
593
def test__remove_simple_descendants(self):
592
594
graph = self.make_graph(ancestry_1)
593
595
self.assertRemoveDescendants({b'rev1'}, graph,
594
{b'rev1', b'rev2a', b'rev2b', b'rev3', b'rev4'})
596
{b'rev1', b'rev2a', b'rev2b', b'rev3', b'rev4'})
596
598
def test__remove_simple_descendants_disjoint(self):
597
599
graph = self.make_graph(ancestry_1)
598
600
self.assertRemoveDescendants({b'rev1', b'rev3'}, graph,
601
603
def test__remove_simple_descendants_chain(self):
602
604
graph = self.make_graph(ancestry_1)
603
605
self.assertRemoveDescendants({b'rev1'}, graph,
604
{b'rev1', b'rev2a', b'rev3'})
606
{b'rev1', b'rev2a', b'rev3'})
606
608
def test__remove_simple_descendants_siblings(self):
607
609
graph = self.make_graph(ancestry_1)
608
610
self.assertRemoveDescendants({b'rev2a', b'rev2b'}, graph,
609
{b'rev2a', b'rev2b', b'rev3'})
611
{b'rev2a', b'rev2b', b'rev3'})
611
613
def test_unique_lca_criss_cross(self):
612
614
"""Ensure we don't pick non-unique lcas in a criss-cross"""
613
615
graph = self.make_graph(criss_cross)
614
616
self.assertEqual(b'rev1', graph.find_unique_lca(b'rev3a', b'rev3b'))
615
lca, steps = graph.find_unique_lca(b'rev3a', b'rev3b', count_steps=True)
617
lca, steps = graph.find_unique_lca(
618
b'rev3a', b'rev3b', count_steps=True)
616
619
self.assertEqual(b'rev1', lca)
617
620
self.assertEqual(2, steps)
652
655
def test_graph_difference(self):
653
656
graph = self.make_graph(ancestry_1)
654
self.assertEqual((set(), set()), graph.find_difference(b'rev1', b'rev1'))
658
(set(), set()), graph.find_difference(b'rev1', b'rev1'))
655
659
self.assertEqual((set(), {b'rev1'}),
656
660
graph.find_difference(NULL_REVISION, b'rev1'))
657
661
self.assertEqual(({b'rev1'}, set()),
948
953
self.assertEqual(({b'head'}, set()), search.next_with_ghosts())
949
954
self.assertEqual(({b'present'}, set()), search.next_with_ghosts())
950
955
self.assertEqual(({b'child'}, {b'ghost'}),
951
search.next_with_ghosts())
956
search.next_with_ghosts())
952
957
self.assertRaises(StopIteration, search.next_with_ghosts)
953
958
# next includes them
954
959
search = graph._make_breadth_first_searcher([b'head'])
955
960
self.assertEqual({b'head'}, next(search))
956
961
self.assertEqual({b'present'}, next(search))
957
962
self.assertEqual({b'child', b'ghost'},
959
964
self.assertRaises(StopIteration, next, search)
961
966
def test_breadth_first_search_change_next_to_next_with_ghosts(self):
971
976
self.assertEqual(({b'head'}, set()), search.next_with_ghosts())
972
977
self.assertEqual({b'present'}, next(search))
973
978
self.assertEqual(({b'child'}, {b'ghost'}),
974
search.next_with_ghosts())
979
search.next_with_ghosts())
975
980
self.assertRaises(StopIteration, next, search)
976
981
# start with next
977
982
search = graph._make_breadth_first_searcher([b'head'])
978
983
self.assertEqual({b'head'}, next(search))
979
984
self.assertEqual(({b'present'}, set()), search.next_with_ghosts())
980
985
self.assertEqual({b'child', b'ghost'},
982
987
self.assertRaises(StopIteration, search.next_with_ghosts)
984
989
def test_breadth_first_change_search(self):
993
998
self.assertEqual(({b'head'}, set()), search.next_with_ghosts())
994
999
self.assertEqual(({b'present'}, set()), search.next_with_ghosts())
995
1000
self.assertEqual({b'present'},
996
search.stop_searching_any([b'present']))
1001
search.stop_searching_any([b'present']))
997
1002
self.assertEqual(({b'other'}, {b'other_ghost'}),
998
search.start_searching([b'other', b'other_ghost']))
1003
search.start_searching([b'other', b'other_ghost']))
999
1004
self.assertEqual(({b'other_2'}, set()), search.next_with_ghosts())
1000
1005
self.assertRaises(StopIteration, search.next_with_ghosts)
1001
1006
# next includes them
1003
1008
self.assertEqual({b'head'}, next(search))
1004
1009
self.assertEqual({b'present'}, next(search))
1005
1010
self.assertEqual({b'present'},
1006
search.stop_searching_any([b'present']))
1011
search.stop_searching_any([b'present']))
1007
1012
search.start_searching([b'other', b'other_ghost'])
1008
1013
self.assertEqual({b'other_2'}, next(search))
1009
1014
self.assertRaises(StopIteration, next, search)
1062
1067
def test_breadth_first_get_result_starts_stops(self):
1063
1068
graph = self.make_graph({
1065
b'child':[NULL_REVISION],
1066
b'otherhead':[b'otherchild'],
1067
b'otherchild':[b'excluded'],
1068
b'excluded':[NULL_REVISION],
1069
b'head': [b'child'],
1070
b'child': [NULL_REVISION],
1071
b'otherhead': [b'otherchild'],
1072
b'otherchild': [b'excluded'],
1073
b'excluded': [NULL_REVISION],
1071
1076
search = graph._make_breadth_first_searcher([])
1072
1077
# Starting with nothing and adding a search works:
1290
1295
def test_multiple_revisions(self):
1291
1296
graph = self.make_graph(ancestry_1)
1292
1297
self.assertFindUniqueAncestors(graph,
1293
[b'rev4'], b'rev4', [b'rev3', b'rev2b'])
1298
[b'rev4'], b'rev4', [b'rev3', b'rev2b'])
1294
1299
self.assertFindUniqueAncestors(graph,
1295
[b'rev2a', b'rev3', b'rev4'], b'rev4', [b'rev2b'])
1300
[b'rev2a', b'rev3', b'rev4'], b'rev4', [b'rev2b'])
1297
1302
def test_complex_shortcut(self):
1298
1303
graph = self.make_graph(complex_shortcut)
1299
1304
self.assertFindUniqueAncestors(graph,
1300
[b'h', b'n'], b'n', [b'm'])
1305
[b'h', b'n'], b'n', [b'm'])
1301
1306
self.assertFindUniqueAncestors(graph,
1302
[b'e', b'i', b'm'], b'm', [b'n'])
1307
[b'e', b'i', b'm'], b'm', [b'n'])
1304
1309
def test_complex_shortcut2(self):
1305
1310
graph = self.make_graph(complex_shortcut2)
1306
1311
self.assertFindUniqueAncestors(graph,
1307
[b'j', b'u'], b'u', [b't'])
1312
[b'j', b'u'], b'u', [b't'])
1308
1313
self.assertFindUniqueAncestors(graph,
1309
[b't'], b't', [b'u'])
1314
[b't'], b't', [b'u'])
1311
1316
def test_multiple_interesting_unique(self):
1312
1317
graph = self.make_graph(multiple_interesting_unique)
1313
1318
self.assertFindUniqueAncestors(graph,
1314
[b'j', b'y'], b'y', [b'z'])
1319
[b'j', b'y'], b'y', [b'z'])
1315
1320
self.assertFindUniqueAncestors(graph,
1316
[b'p', b'z'], b'z', [b'y'])
1321
[b'p', b'z'], b'z', [b'y'])
1318
1323
def test_racing_shortcuts(self):
1319
1324
graph = self.make_graph(racing_shortcuts)
1320
1325
self.assertFindUniqueAncestors(graph,
1321
[b'p', b'q', b'z'], b'z', [b'y'])
1326
[b'p', b'q', b'z'], b'z', [b'y'])
1322
1327
self.assertFindUniqueAncestors(graph,
1323
[b'h', b'i', b'j', b'y'], b'j', [b'z'])
1328
[b'h', b'i', b'j', b'y'], b'j', [b'z'])
1326
1331
class TestGraphFindDistanceToNull(TestGraphBase):
1390
1395
def test_parents(self):
1391
1396
graph = self.make_graph(ancestry_1)
1392
1397
self.assertMergeOrder([b'rev3', b'rev2b'], graph, b'rev4',
1393
[b'rev3', b'rev2b'])
1398
[b'rev3', b'rev2b'])
1394
1399
self.assertMergeOrder([b'rev3', b'rev2b'], graph, b'rev4',
1395
[b'rev2b', b'rev3'])
1400
[b'rev2b', b'rev3'])
1397
1402
def test_ancestors(self):
1398
1403
graph = self.make_graph(ancestry_1)
1399
1404
self.assertMergeOrder([b'rev1', b'rev2b'], graph, b'rev4',
1400
[b'rev1', b'rev2b'])
1405
[b'rev1', b'rev2b'])
1401
1406
self.assertMergeOrder([b'rev1', b'rev2b'], graph, b'rev4',
1402
[b'rev2b', b'rev1'])
1407
[b'rev2b', b'rev1'])
1404
1409
def test_shortcut_one_ancestor(self):
1405
1410
# When we have enough info, we can stop searching
1406
graph = self.make_breaking_graph(ancestry_1, [b'rev3', b'rev2b', b'rev4'])
1411
graph = self.make_breaking_graph(
1412
ancestry_1, [b'rev3', b'rev2b', b'rev4'])
1407
1413
# Single ancestors shortcut right away
1408
1414
self.assertMergeOrder([b'rev3'], graph, b'rev4', [b'rev3'])
1410
1416
def test_shortcut_after_one_ancestor(self):
1411
1417
graph = self.make_breaking_graph(ancestry_1, [b'rev2a', b'rev2b'])
1412
self.assertMergeOrder([b'rev3', b'rev1'], graph, b'rev4', [b'rev1', b'rev3'])
1418
self.assertMergeOrder([b'rev3', b'rev1'], graph,
1419
b'rev4', [b'rev1', b'rev3'])
1415
1422
class TestFindDescendants(TestGraphBase):
1484
1492
def test_get_parent_map(self):
1485
1493
"""Requesting the same revision should be returned from cache"""
1486
1494
self.assertEqual({}, self.caching_pp._cache)
1487
self.assertEqual({b'a':(b'b',)}, self.caching_pp.get_parent_map([b'a']))
1496
{b'a': (b'b',)}, self.caching_pp.get_parent_map([b'a']))
1488
1497
self.assertEqual([b'a'], self.inst_pp.calls)
1489
self.assertEqual({b'a':(b'b',)}, self.caching_pp.get_parent_map([b'a']))
1499
{b'a': (b'b',)}, self.caching_pp.get_parent_map([b'a']))
1490
1500
# No new call, as it should have been returned from the cache
1491
1501
self.assertEqual([b'a'], self.inst_pp.calls)
1492
self.assertEqual({b'a':(b'b',)}, self.caching_pp._cache)
1502
self.assertEqual({b'a': (b'b',)}, self.caching_pp._cache)
1494
1504
def test_get_parent_map_not_present(self):
1495
1505
"""The cache should also track when a revision doesn't exist"""
1503
1513
"""Anything that can be returned from cache, should be"""
1504
1514
self.assertEqual({}, self.caching_pp.get_parent_map([b'b']))
1505
1515
self.assertEqual([b'b'], self.inst_pp.calls)
1506
self.assertEqual({b'a':(b'b',)},
1516
self.assertEqual({b'a': (b'b',)},
1507
1517
self.caching_pp.get_parent_map([b'a', b'b']))
1508
1518
self.assertEqual([b'b', b'a'], self.inst_pp.calls)
1510
1520
def test_get_parent_map_repeated(self):
1511
1521
"""Asking for the same parent 2x will only forward 1 request."""
1512
self.assertEqual({b'a':(b'b',)},
1522
self.assertEqual({b'a': (b'b',)},
1513
1523
self.caching_pp.get_parent_map([b'b', b'a', b'b']))
1514
1524
# Use sorted because we don't care about the order, just that each is
1515
1525
# only present 1 time.
1525
1535
def test_get_cached_parent_map(self):
1526
1536
self.assertEqual({}, self.caching_pp.get_cached_parent_map([b'a']))
1527
1537
self.assertEqual([], self.inst_pp.calls)
1528
self.assertEqual({b'a': (b'b',)}, self.caching_pp.get_parent_map([b'a']))
1539
{b'a': (b'b',)}, self.caching_pp.get_parent_map([b'a']))
1529
1540
self.assertEqual([b'a'], self.inst_pp.calls)
1530
1541
self.assertEqual({b'a': (b'b',)},
1531
1542
self.caching_pp.get_cached_parent_map([b'a']))
1610
1621
_mod_graph.collapse_linear_regions(original))
1612
1623
def test_collapse_nothing(self):
1613
d = {1:[2, 3], 2:[], 3:[]}
1624
d = {1: [2, 3], 2: [], 3: []}
1614
1625
self.assertCollapsed(d, d)
1615
d = {1:[2], 2:[3, 4], 3:[5], 4:[5], 5:[]}
1626
d = {1: [2], 2: [3, 4], 3: [5], 4: [5], 5: []}
1616
1627
self.assertCollapsed(d, d)
1618
1629
def test_collapse_chain(self):
1619
1630
# Any time we have a linear chain, we should be able to collapse
1620
d = {1:[2], 2:[3], 3:[4], 4:[5], 5:[]}
1621
self.assertCollapsed({1:[5], 5:[]}, d)
1622
d = {5:[4], 4:[3], 3:[2], 2:[1], 1:[]}
1623
self.assertCollapsed({5:[1], 1:[]}, d)
1624
d = {5:[3], 3:[4], 4:[1], 1:[2], 2:[]}
1625
self.assertCollapsed({5:[2], 2:[]}, d)
1631
d = {1: [2], 2: [3], 3: [4], 4: [5], 5: []}
1632
self.assertCollapsed({1: [5], 5: []}, d)
1633
d = {5: [4], 4: [3], 3: [2], 2: [1], 1: []}
1634
self.assertCollapsed({5: [1], 1: []}, d)
1635
d = {5: [3], 3: [4], 4: [1], 1: [2], 2: []}
1636
self.assertCollapsed({5: [2], 2: []}, d)
1627
1638
def test_collapse_with_multiple_children(self):
1638
1649
# 4 and 5 cannot be removed because 6 has 2 children
1639
1650
# 2 and 3 cannot be removed because 1 has 2 parents
1640
d = {1:[2, 3], 2:[4], 4:[6], 3:[5], 5:[6], 6:[7], 7:[]}
1651
d = {1: [2, 3], 2: [4], 4: [6], 3: [5], 5: [6], 6: [7], 7: []}
1641
1652
self.assertCollapsed(d, d)
1652
d = {(b'D',): [(b'B',), (b'C',)], (b'C',):[(b'A',)],
1663
d = {(b'D',): [(b'B',), (b'C',)], (b'C',): [(b'A',)],
1653
1664
(b'B',): [(b'A',)], (b'A',): []}
1654
1665
g = _mod_graph.Graph(_mod_graph.DictParentsProvider(d))
1655
1666
graph_thunk = _mod_graph.GraphThunkIdsToKeys(g)
1659
1670
self.assertEqual([b'B', b'C'], sorted(graph_thunk.heads([b'B', b'C'])))
1661
1672
def test_add_node(self):
1662
d = {(b'C',):[(b'A',)], (b'B',): [(b'A',)], (b'A',): []}
1673
d = {(b'C',): [(b'A',)], (b'B',): [(b'A',)], (b'A',): []}
1663
1674
g = _mod_graph.KnownGraph(d)
1664
1675
graph_thunk = _mod_graph.GraphThunkIdsToKeys(g)
1665
1676
graph_thunk.add_node(b"D", [b"A", b"C"])
1666
1677
self.assertEqual([b'B', b'D'],
1667
sorted(graph_thunk.heads([b'D', b'B', b'A'])))
1678
sorted(graph_thunk.heads([b'D', b'B', b'A'])))
1669
1680
def test_merge_sort(self):
1670
d = {(b'C',):[(b'A',)], (b'B',): [(b'A',)], (b'A',): []}
1681
d = {(b'C',): [(b'A',)], (b'B',): [(b'A',)], (b'A',): []}
1671
1682
g = _mod_graph.KnownGraph(d)
1672
1683
graph_thunk = _mod_graph.GraphThunkIdsToKeys(g)
1673
1684
graph_thunk.add_node(b"D", [b"A", b"C"])
1674
1685
self.assertEqual([(b'C', 0, (2,), False), (b'A', 0, (1,), True)],
1675
[(n.key, n.merge_depth, n.revno, n.end_of_merge)
1676
for n in graph_thunk.merge_sort(b'C')])
1686
[(n.key, n.merge_depth, n.revno, n.end_of_merge)
1687
for n in graph_thunk.merge_sort(b'C')])
1679
1690
class TestStackedParentsProvider(tests.TestCase):
1692
1703
parents1 = _mod_graph.DictParentsProvider({b'rev2': [b'rev3']})
1693
1704
parents2 = _mod_graph.DictParentsProvider({b'rev1': [b'rev4']})
1694
1705
stacked = _mod_graph.StackedParentsProvider([parents1, parents2])
1695
self.assertEqual({b'rev1':[b'rev4'], b'rev2':[b'rev3']},
1706
self.assertEqual({b'rev1': [b'rev4'], b'rev2': [b'rev3']},
1696
1707
stacked.get_parent_map([b'rev1', b'rev2']))
1697
self.assertEqual({b'rev2':[b'rev3'], b'rev1':[b'rev4']},
1708
self.assertEqual({b'rev2': [b'rev3'], b'rev1': [b'rev4']},
1698
1709
stacked.get_parent_map([b'rev2', b'rev1']))
1699
self.assertEqual({b'rev2':[b'rev3']},
1710
self.assertEqual({b'rev2': [b'rev3']},
1700
1711
stacked.get_parent_map([b'rev2', b'rev2']))
1701
self.assertEqual({b'rev1':[b'rev4']},
1712
self.assertEqual({b'rev1': [b'rev4']},
1702
1713
stacked.get_parent_map([b'rev1', b'rev1']))
1704
1715
def test_stacked_parents_provider_overlapping(self):
1720
1731
pp2 = self.get_shared_provider(b'pp2', {b'rev2': (b'rev1',)},
1721
1732
has_cached=True)
1722
1733
stacked = _mod_graph.StackedParentsProvider([pp1, pp2])
1723
self.assertEqual({b'rev2': (b'rev1',)}, stacked.get_parent_map([b'rev2']))
1734
self.assertEqual({b'rev2': (b'rev1',)},
1735
stacked.get_parent_map([b'rev2']))
1724
1736
# No call on b'pp1' because it doesn't provide get_cached_parent_map
1725
1737
self.assertEqual([(b'pp2', 'cached', [b'rev2'])], self.calls)
1729
1741
# get_parent_map. Further, we should track what entries we have found,
1730
1742
# and not re-try them.
1731
1743
pp1 = self.get_shared_provider(b'pp1', {b'a': ()}, has_cached=True)
1732
pp2 = self.get_shared_provider(b'pp2', {b'c': (b'b',)}, has_cached=False)
1733
pp3 = self.get_shared_provider(b'pp3', {b'b': (b'a',)}, has_cached=True)
1744
pp2 = self.get_shared_provider(
1745
b'pp2', {b'c': (b'b',)}, has_cached=False)
1746
pp3 = self.get_shared_provider(
1747
b'pp3', {b'b': (b'a',)}, has_cached=True)
1734
1748
stacked = _mod_graph.StackedParentsProvider([pp1, pp2, pp3])
1735
1749
self.assertEqual({b'a': (), b'b': (b'a',), b'c': (b'b',)},
1736
1750
stacked.get_parent_map([b'a', b'b', b'c', b'd']))