681
646
self.assertEqual(set(['h1', 'h2']),
682
647
self._run_heads_break_deeper(graph_dict, ['h1', 'h2']))
649
def test_breadth_first_search_start_ghosts(self):
650
graph = self.make_graph({})
651
# with_ghosts reports the ghosts
652
search = graph._make_breadth_first_searcher(['a-ghost'])
653
self.assertEqual((set(), set(['a-ghost'])), search.next_with_ghosts())
654
self.assertRaises(StopIteration, search.next_with_ghosts)
656
search = graph._make_breadth_first_searcher(['a-ghost'])
657
self.assertEqual(set(['a-ghost']), search.next())
658
self.assertRaises(StopIteration, search.next)
660
def test_breadth_first_search_deep_ghosts(self):
661
graph = self.make_graph({
663
'present':['child', 'ghost'],
666
# with_ghosts reports the ghosts
667
search = graph._make_breadth_first_searcher(['head'])
668
self.assertEqual((set(['head']), set()), search.next_with_ghosts())
669
self.assertEqual((set(['present']), set()), search.next_with_ghosts())
670
self.assertEqual((set(['child']), set(['ghost'])),
671
search.next_with_ghosts())
672
self.assertRaises(StopIteration, search.next_with_ghosts)
674
search = graph._make_breadth_first_searcher(['head'])
675
self.assertEqual(set(['head']), search.next())
676
self.assertEqual(set(['present']), search.next())
677
self.assertEqual(set(['child', 'ghost']),
679
self.assertRaises(StopIteration, search.next)
681
def test_breadth_first_search_change_next_to_next_with_ghosts(self):
682
# To make the API robust, we allow calling both next() and
683
# next_with_ghosts() on the same searcher.
684
graph = self.make_graph({
686
'present':['child', 'ghost'],
689
# start with next_with_ghosts
690
search = graph._make_breadth_first_searcher(['head'])
691
self.assertEqual((set(['head']), set()), search.next_with_ghosts())
692
self.assertEqual(set(['present']), search.next())
693
self.assertEqual((set(['child']), set(['ghost'])),
694
search.next_with_ghosts())
695
self.assertRaises(StopIteration, search.next)
697
search = graph._make_breadth_first_searcher(['head'])
698
self.assertEqual(set(['head']), search.next())
699
self.assertEqual((set(['present']), set()), search.next_with_ghosts())
700
self.assertEqual(set(['child', 'ghost']),
702
self.assertRaises(StopIteration, search.next_with_ghosts)
704
def test_breadth_first_change_search(self):
705
# Changing the search should work with both next and next_with_ghosts.
706
graph = self.make_graph({
708
'present':['stopped'],
712
search = graph._make_breadth_first_searcher(['head'])
713
self.assertEqual((set(['head']), set()), search.next_with_ghosts())
714
self.assertEqual((set(['present']), set()), search.next_with_ghosts())
715
self.assertEqual(set(['present']),
716
search.stop_searching_any(['present']))
717
self.assertEqual((set(['other']), set(['other_ghost'])),
718
search.start_searching(['other', 'other_ghost']))
719
self.assertEqual((set(['other_2']), set()), search.next_with_ghosts())
720
self.assertRaises(StopIteration, search.next_with_ghosts)
722
search = graph._make_breadth_first_searcher(['head'])
723
self.assertEqual(set(['head']), search.next())
724
self.assertEqual(set(['present']), search.next())
725
self.assertEqual(set(['present']),
726
search.stop_searching_any(['present']))
727
search.start_searching(['other', 'other_ghost'])
728
self.assertEqual(set(['other_2']), search.next())
729
self.assertRaises(StopIteration, search.next)
731
def assertSeenAndResult(self, instructions, search, next):
732
"""Check the results of .seen and get_result() for a seach.
734
:param instructions: A list of tuples:
735
(seen, recipe, included_keys, starts, stops).
736
seen, recipe and included_keys are results to check on the search
737
and the searches get_result(). starts and stops are parameters to
738
pass to start_searching and stop_searching_any during each
739
iteration, if they are not None.
740
:param search: The search to use.
741
:param next: A callable to advance the search.
743
for seen, recipe, included_keys, starts, stops in instructions:
745
if starts is not None:
746
search.start_searching(starts)
747
if stops is not None:
748
search.stop_searching_any(stops)
749
result = search.get_result()
750
self.assertEqual(recipe, result.get_recipe())
751
self.assertEqual(set(included_keys), result.get_keys())
752
self.assertEqual(seen, search.seen)
754
def test_breadth_first_get_result_excludes_current_pending(self):
755
graph = self.make_graph({
757
'child':[NULL_REVISION],
760
search = graph._make_breadth_first_searcher(['head'])
761
# At the start, nothing has been seen, to its all excluded:
762
result = search.get_result()
763
self.assertEqual((set(['head']), set(['head']), 0),
765
self.assertEqual(set(), result.get_keys())
766
self.assertEqual(set(), search.seen)
769
(set(['head']), (set(['head']), set(['child']), 1),
770
['head'], None, None),
771
(set(['head', 'child']), (set(['head']), set([NULL_REVISION]), 2),
772
['head', 'child'], None, None),
773
(set(['head', 'child', NULL_REVISION]), (set(['head']), set(), 3),
774
['head', 'child', NULL_REVISION], None, None),
776
self.assertSeenAndResult(expected, search, search.next)
777
# using next_with_ghosts:
778
search = graph._make_breadth_first_searcher(['head'])
779
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
781
def test_breadth_first_get_result_starts_stops(self):
782
graph = self.make_graph({
784
'child':[NULL_REVISION],
785
'otherhead':['otherchild'],
786
'otherchild':['excluded'],
787
'excluded':[NULL_REVISION],
790
search = graph._make_breadth_first_searcher([])
791
# Starting with nothing and adding a search works:
792
search.start_searching(['head'])
793
# head has been seen:
794
result = search.get_result()
795
self.assertEqual((set(['head']), set(['child']), 1),
797
self.assertEqual(set(['head']), result.get_keys())
798
self.assertEqual(set(['head']), search.seen)
801
# stop at child, and start a new search at otherhead:
802
# - otherhead counts as seen immediately when start_searching is
804
(set(['head', 'child', 'otherhead']),
805
(set(['head', 'otherhead']), set(['child', 'otherchild']), 2),
806
['head', 'otherhead'], ['otherhead'], ['child']),
807
(set(['head', 'child', 'otherhead', 'otherchild']),
808
(set(['head', 'otherhead']), set(['child', 'excluded']), 3),
809
['head', 'otherhead', 'otherchild'], None, None),
810
# stop searching excluded now
811
(set(['head', 'child', 'otherhead', 'otherchild', 'excluded']),
812
(set(['head', 'otherhead']), set(['child', 'excluded']), 3),
813
['head', 'otherhead', 'otherchild'], None, ['excluded']),
815
self.assertSeenAndResult(expected, search, search.next)
816
# using next_with_ghosts:
817
search = graph._make_breadth_first_searcher([])
818
search.start_searching(['head'])
819
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
821
def test_breadth_first_stop_searching_not_queried(self):
822
# A client should be able to say 'stop node X' even if X has not been
823
# returned to the client.
824
graph = self.make_graph({
825
'head':['child', 'ghost1'],
826
'child':[NULL_REVISION],
829
search = graph._make_breadth_first_searcher(['head'])
831
# NULL_REVISION and ghost1 have not been returned
832
(set(['head']), (set(['head']), set(['child', 'ghost1']), 1),
833
['head'], None, [NULL_REVISION, 'ghost1']),
834
# ghost1 has been returned, NULL_REVISION is to be returned in the
836
(set(['head', 'child', 'ghost1']),
837
(set(['head']), set(['ghost1', NULL_REVISION]), 2),
838
['head', 'child'], None, [NULL_REVISION, 'ghost1']),
840
self.assertSeenAndResult(expected, search, search.next)
841
# using next_with_ghosts:
842
search = graph._make_breadth_first_searcher(['head'])
843
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
845
def test_breadth_first_get_result_ghosts_are_excluded(self):
846
graph = self.make_graph({
847
'head':['child', 'ghost'],
848
'child':[NULL_REVISION],
851
search = graph._make_breadth_first_searcher(['head'])
855
(set(['head']), set(['ghost', 'child']), 1),
856
['head'], None, None),
857
(set(['head', 'child', 'ghost']),
858
(set(['head']), set([NULL_REVISION, 'ghost']), 2),
859
['head', 'child'], None, None),
861
self.assertSeenAndResult(expected, search, search.next)
862
# using next_with_ghosts:
863
search = graph._make_breadth_first_searcher(['head'])
864
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
866
def test_breadth_first_get_result_starting_a_ghost_ghost_is_excluded(self):
867
graph = self.make_graph({
869
'child':[NULL_REVISION],
872
search = graph._make_breadth_first_searcher(['head'])
875
(set(['head', 'ghost']),
876
(set(['head', 'ghost']), set(['child', 'ghost']), 1),
877
['head'], ['ghost'], None),
878
(set(['head', 'child', 'ghost']),
879
(set(['head', 'ghost']), set([NULL_REVISION, 'ghost']), 2),
880
['head', 'child'], None, None),
882
self.assertSeenAndResult(expected, search, search.next)
883
# using next_with_ghosts:
884
search = graph._make_breadth_first_searcher(['head'])
885
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
887
def test_breadth_first_revision_count_includes_NULL_REVISION(self):
888
graph = self.make_graph({
889
'head':[NULL_REVISION],
892
search = graph._make_breadth_first_searcher(['head'])
896
(set(['head']), set([NULL_REVISION]), 1),
897
['head'], None, None),
898
(set(['head', NULL_REVISION]),
899
(set(['head']), set([]), 2),
900
['head', NULL_REVISION], None, None),
902
self.assertSeenAndResult(expected, search, search.next)
903
# using next_with_ghosts:
904
search = graph._make_breadth_first_searcher(['head'])
905
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
907
def test_breadth_first_search_get_result_after_StopIteration(self):
908
# StopIteration should not invalid anything..
909
graph = self.make_graph({
910
'head':[NULL_REVISION],
913
search = graph._make_breadth_first_searcher(['head'])
917
(set(['head']), set([NULL_REVISION]), 1),
918
['head'], None, None),
919
(set(['head', 'ghost', NULL_REVISION]),
920
(set(['head', 'ghost']), set(['ghost']), 2),
921
['head', NULL_REVISION], ['ghost'], None),
923
self.assertSeenAndResult(expected, search, search.next)
924
self.assertRaises(StopIteration, search.next)
925
self.assertEqual(set(['head', 'ghost', NULL_REVISION]), search.seen)
926
result = search.get_result()
927
self.assertEqual((set(['ghost', 'head']), set(['ghost']), 2),
929
self.assertEqual(set(['head', NULL_REVISION]), result.get_keys())
930
# using next_with_ghosts:
931
search = graph._make_breadth_first_searcher(['head'])
932
self.assertSeenAndResult(expected, search, search.next_with_ghosts)
933
self.assertRaises(StopIteration, search.next)
934
self.assertEqual(set(['head', 'ghost', NULL_REVISION]), search.seen)
935
result = search.get_result()
936
self.assertEqual((set(['ghost', 'head']), set(['ghost']), 2),
938
self.assertEqual(set(['head', NULL_REVISION]), result.get_keys())
685
941
class TestCachingParentsProvider(tests.TestCase):