1011
1014
search = graph._make_breadth_first_searcher(['head'])
1012
1015
# At the start, nothing has been seen, to its all excluded:
1013
1016
result = search.get_result()
1014
self.assertEqual((set(['head']), set(['head']), 0),
1017
self.assertEqual(('search', set(['head']), set(['head']), 0),
1015
1018
result.get_recipe())
1016
1019
self.assertEqual(set(), result.get_keys())
1017
1020
self.assertEqual(set(), search.seen)
1203
1206
self.assertRaises(StopIteration, search.next)
1204
1207
self.assertEqual(set(['head', 'ghost', NULL_REVISION]), search.seen)
1205
1208
result = search.get_result()
1206
self.assertEqual((set(['ghost', 'head']), set(['ghost']), 2),
1209
self.assertEqual(('search', set(['ghost', 'head']), set(['ghost']), 2),
1207
1210
result.get_recipe())
1208
1211
self.assertEqual(set(['head', NULL_REVISION]), result.get_keys())
1209
1212
# using next_with_ghosts:
1212
1215
self.assertRaises(StopIteration, search.next)
1213
1216
self.assertEqual(set(['head', 'ghost', NULL_REVISION]), search.seen)
1214
1217
result = search.get_result()
1215
self.assertEqual((set(['ghost', 'head']), set(['ghost']), 2),
1218
self.assertEqual(('search', set(['ghost', 'head']), set(['ghost']), 2),
1216
1219
result.get_recipe())
1217
1220
self.assertEqual(set(['head', NULL_REVISION]), result.get_keys())
1424
1432
# only present 1 time.
1425
1433
self.assertEqual(['a', 'b'], sorted(self.inst_pp.calls))
1435
def test_note_missing_key(self):
1436
"""After noting that a key is missing it is cached."""
1437
self.caching_pp.note_missing_key('b')
1438
self.assertEqual({}, self.caching_pp.get_parent_map(['b']))
1439
self.assertEqual([], self.inst_pp.calls)
1440
self.assertEqual(set(['b']), self.caching_pp.missing_keys)
1428
1443
class TestCachingParentsProviderExtras(tests.TestCaseWithTransport):
1429
1444
"""Test the behaviour when parents are provided that were not requested."""
1540
1555
repo = builder.get_branch().repository
1541
1556
repo.lock_read()
1542
1557
self.addCleanup(repo.unlock)
1543
par = _mod_graph.PendingAncestryResult(['rev-2'], repo)
1544
self.assertEqual(set(['rev-1', 'rev-2']), set(par.get_keys()))
1558
result = _mod_graph.PendingAncestryResult(['rev-2'], repo)
1559
self.assertEqual(set(['rev-1', 'rev-2']), set(result.get_keys()))
1561
def test_get_keys_excludes_ghosts(self):
1562
builder = self.make_branch_builder('b')
1563
builder.start_series()
1564
builder.build_snapshot('rev-1', None, [
1565
('add', ('', 'root-id', 'directory', ''))])
1566
builder.build_snapshot('rev-2', ['rev-1', 'ghost'], [])
1567
builder.finish_series()
1568
repo = builder.get_branch().repository
1570
self.addCleanup(repo.unlock)
1571
result = _mod_graph.PendingAncestryResult(['rev-2'], repo)
1572
self.assertEqual(sorted(['rev-1', 'rev-2']), sorted(result.get_keys()))
1546
1574
def test_get_keys_excludes_null(self):
1547
1575
# Make a 'graph' with an iter_ancestry that returns NULL_REVISION
1550
1578
class StubGraph(object):
1551
1579
def iter_ancestry(self, keys):
1552
1580
return [(NULL_REVISION, ()), ('foo', (NULL_REVISION,))]
1553
par = _mod_graph.PendingAncestryResult(['rev-3'], None)
1554
par_keys = par._get_keys(StubGraph())
1581
result = _mod_graph.PendingAncestryResult(['rev-3'], None)
1582
result_keys = result._get_keys(StubGraph())
1555
1583
# Only the non-null keys from the ancestry appear.
1556
self.assertEqual(set(['foo']), set(par_keys))
1584
self.assertEqual(set(['foo']), set(result_keys))
1587
class TestPendingAncestryResultRefine(TestGraphBase):
1589
def test_refine(self):
1590
# Used when pulling from a stacked repository, so test some revisions
1591
# being satisfied from the stacking branch.
1592
g = self.make_graph(
1593
{"tip":["mid"], "mid":["base"], "tag":["base"],
1594
"base":[NULL_REVISION], NULL_REVISION:[]})
1595
result = _mod_graph.PendingAncestryResult(['tip', 'tag'], None)
1596
result = result.refine(set(['tip']), set(['mid']))
1597
self.assertEqual(set(['mid', 'tag']), result.heads)
1598
result = result.refine(set(['mid', 'tag', 'base']),
1599
set([NULL_REVISION]))
1600
self.assertEqual(set([NULL_REVISION]), result.heads)
1601
self.assertTrue(result.is_empty())
1604
class TestSearchResultRefine(TestGraphBase):
1606
def test_refine(self):
1607
# Used when pulling from a stacked repository, so test some revisions
1608
# being satisfied from the stacking branch.
1609
g = self.make_graph(
1610
{"tip":["mid"], "mid":["base"], "tag":["base"],
1611
"base":[NULL_REVISION], NULL_REVISION:[]})
1612
result = _mod_graph.SearchResult(set(['tip', 'tag']),
1613
set([NULL_REVISION]), 4, set(['tip', 'mid', 'tag', 'base']))
1614
result = result.refine(set(['tip']), set(['mid']))
1615
recipe = result.get_recipe()
1616
# We should be starting from tag (original head) and mid (seen ref)
1617
self.assertEqual(set(['mid', 'tag']), recipe[1])
1618
# We should be stopping at NULL (original stop) and tip (seen head)
1619
self.assertEqual(set([NULL_REVISION, 'tip']), recipe[2])
1620
self.assertEqual(3, recipe[3])
1621
result = result.refine(set(['mid', 'tag', 'base']),
1622
set([NULL_REVISION]))
1623
recipe = result.get_recipe()
1624
# We should be starting from nothing (NULL was known as a cut point)
1625
self.assertEqual(set([]), recipe[1])
1626
# We should be stopping at NULL (original stop) and tip (seen head) and
1627
# tag (seen head) and mid(seen mid-point head). We could come back and
1628
# define this as not including mid, for minimal results, but it is
1629
# still 'correct' to include mid, and simpler/easier.
1630
self.assertEqual(set([NULL_REVISION, 'tip', 'tag', 'mid']), recipe[2])
1631
self.assertEqual(0, recipe[3])
1632
self.assertTrue(result.is_empty())