~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_knit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-07-25 02:47:25 UTC
  • mfrom: (2625.8.2 knits)
  • Revision ID: pqm@pqm.ubuntu.com-20070725024725-x592w4y7gdqxv81x
(robertc) Allow the adaption of Knits to external indices via KnitGraphIndex. (Robert Collins).

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    RevisionNotPresent,
34
34
    NoSuchFile,
35
35
    )
 
36
from bzrlib.index import *
36
37
from bzrlib.knit import (
37
38
    KnitContent,
 
39
    KnitGraphIndex,
38
40
    KnitVersionedFile,
39
41
    KnitPlainFactory,
40
42
    KnitAnnotateFactory,
357
359
            ])
358
360
        index = self.get_knit_index(transport, "filename", "r")
359
361
        self.assertEqual(2, index.num_versions())
360
 
        self.assertEqual(1, index.lookup("version"))
 
362
        # check that the index used is the first one written. (Specific
 
363
        # to KnitIndex style indices.
 
364
        self.assertEqual("1", index._version_list_to_index(["version"]))
361
365
        self.assertEqual((3, 4), index.get_position("version"))
362
366
        self.assertEqual(["options3"], index.get_options("version"))
363
367
        self.assertEqual(["parent", "other"],
461
465
        self.assertRaises(RevisionNotPresent,
462
466
            index.get_ancestry_with_ghosts, ["e"])
463
467
 
 
468
    def test_iter_parents(self):
 
469
        transport = MockTransport()
 
470
        index = self.get_knit_index(transport, "filename", "w", create=True)
 
471
        # no parents
 
472
        index.add_version('r0', ['option'], 0, 1, [])
 
473
        # 1 parent
 
474
        index.add_version('r1', ['option'], 0, 1, ['r0'])
 
475
        # 2 parents
 
476
        index.add_version('r2', ['option'], 0, 1, ['r1', 'r0'])
 
477
        # XXX TODO a ghost
 
478
        # cases: each sample data individually:
 
479
        self.assertEqual(set([('r0', ())]),
 
480
            set(index.iter_parents(['r0'])))
 
481
        self.assertEqual(set([('r1', ('r0', ))]),
 
482
            set(index.iter_parents(['r1'])))
 
483
        self.assertEqual(set([('r2', ('r1', 'r0'))]),
 
484
            set(index.iter_parents(['r2'])))
 
485
        # no nodes returned for a missing node
 
486
        self.assertEqual(set(),
 
487
            set(index.iter_parents(['missing'])))
 
488
        # 1 node returned with missing nodes skipped
 
489
        self.assertEqual(set([('r1', ('r0', ))]),
 
490
            set(index.iter_parents(['ghost1', 'r1', 'ghost'])))
 
491
        # 2 nodes returned
 
492
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
 
493
            set(index.iter_parents(['r0', 'r1'])))
 
494
        # 2 nodes returned, missing skipped
 
495
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
 
496
            set(index.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))
 
497
 
464
498
    def test_num_versions(self):
465
499
        transport = MockTransport([
466
500
            _KnitIndex.HEADER
499
533
        index.add_version("b", ["option"], 0, 1, [])
500
534
        self.assertEqual(["a", "b"], index.get_versions())
501
535
 
502
 
    def test_idx_to_name(self):
503
 
        transport = MockTransport([
504
 
            _KnitIndex.HEADER,
505
 
            "a option 0 1 :",
506
 
            "b option 0 1 :"
507
 
            ])
508
 
        index = self.get_knit_index(transport, "filename", "r")
509
 
 
510
 
        self.assertEqual("a", index.idx_to_name(0))
511
 
        self.assertEqual("b", index.idx_to_name(1))
512
 
        self.assertEqual("b", index.idx_to_name(-1))
513
 
        self.assertEqual("a", index.idx_to_name(-2))
514
 
 
515
 
    def test_lookup(self):
516
 
        transport = MockTransport([
517
 
            _KnitIndex.HEADER,
518
 
            "a option 0 1 :",
519
 
            "b option 0 1 :"
520
 
            ])
521
 
        index = self.get_knit_index(transport, "filename", "r")
522
 
 
523
 
        self.assertEqual(0, index.lookup("a"))
524
 
        self.assertEqual(1, index.lookup("b"))
525
 
 
526
536
    def test_add_version(self):
527
537
        transport = MockTransport([
528
538
            _KnitIndex.HEADER
846
856
class KnitTests(TestCaseWithTransport):
847
857
    """Class containing knit test helper routines."""
848
858
 
849
 
    def make_test_knit(self, annotate=False, delay_create=False):
 
859
    def make_test_knit(self, annotate=False, delay_create=False, index=None):
850
860
        if not annotate:
851
861
            factory = KnitPlainFactory()
852
862
        else:
853
863
            factory = None
854
864
        return KnitVersionedFile('test', get_transport('.'), access_mode='w',
855
865
                                 factory=factory, create=True,
856
 
                                 delay_create=delay_create)
 
866
                                 delay_create=delay_create, index=index)
857
867
 
858
868
 
859
869
class BasicKnitTests(KnitTests):
866
876
        """Construct empty k"""
867
877
        self.make_test_knit()
868
878
 
 
879
    def test_make_explicit_index(self):
 
880
        """We can supply an index to use."""
 
881
        knit = KnitVersionedFile('test', get_transport('.'),
 
882
            index='strangelove')
 
883
        self.assertEqual(knit._index, 'strangelove')
 
884
 
869
885
    def test_knit_add(self):
870
886
        """Store one text in knit and retrieve"""
871
887
        k = self.make_test_knit()
989
1005
        k.clear_cache()
990
1006
        self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A)
991
1007
 
 
1008
    def test_add_delta_knit_graph_index(self):
 
1009
        """Does adding work with a KnitGraphIndex."""
 
1010
        index = InMemoryGraphIndex(2)
 
1011
        knit_index = KnitGraphIndex(index, add_callback=index.add_nodes,
 
1012
            deltas=True)
 
1013
        k = KnitVersionedFile('test', get_transport('.'),
 
1014
            delta=True, create=True, index=knit_index)
 
1015
        self.add_stock_one_and_one_a(k)
 
1016
        k.clear_cache()
 
1017
        self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A)
 
1018
        # check the index had the right data added.
 
1019
        self.assertEqual(set([
 
1020
            ('text-1', ' 0 127', ((), ())),
 
1021
            ('text-1a', ' 127 140', (('text-1',), ('text-1',))),
 
1022
            ]), set(index.iter_all_entries()))
 
1023
        # we should not have a .kndx file
 
1024
        self.assertFalse(get_transport('.').has('test.kndx'))
 
1025
 
992
1026
    def test_annotate(self):
993
1027
        """Annotations"""
994
1028
        k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(),
1565
1599
        t.put_bytes('test.kndx', '# not really a knit header\n\n')
1566
1600
 
1567
1601
        self.assertRaises(KnitHeaderError, self.make_test_knit)
 
1602
 
 
1603
 
 
1604
class TestGraphIndexKnit(KnitTests):
 
1605
    """Tests for knits using a GraphIndex rather than a KnitIndex."""
 
1606
 
 
1607
    def make_g_index(self, name, ref_lists=0, nodes=[]):
 
1608
        builder = GraphIndexBuilder(ref_lists)
 
1609
        for node, references, value in nodes:
 
1610
            builder.add_node(node, references, value)
 
1611
        stream = builder.finish()
 
1612
        trans = self.get_transport()
 
1613
        trans.put_file(name, stream)
 
1614
        return GraphIndex(trans, name)
 
1615
 
 
1616
    def two_graph_index(self, deltas=False, catch_adds=False):
 
1617
        """Build a two-graph index.
 
1618
 
 
1619
        :param deltas: If true, use underlying indices with two node-ref
 
1620
            lists and 'parent' set to a delta-compressed against tail.
 
1621
        """
 
1622
        # build a complex graph across several indices.
 
1623
        if deltas:
 
1624
            index1 = self.make_g_index('1', 2, [
 
1625
                ('tip', 'N0 100', (['parent'], [], )),
 
1626
                ('tail', '', ([], []))])
 
1627
            index2 = self.make_g_index('2', 2, [
 
1628
                ('parent', ' 100 78', (['tail', 'ghost'], ['tail'])),
 
1629
                ('separate', '', ([], []))])
 
1630
        else:
 
1631
            index1 = self.make_g_index('1', 1, [
 
1632
                ('tip', 'N0 100', (['parent'], )),
 
1633
                ('tail', '', ([], ))])
 
1634
            index2 = self.make_g_index('2', 1, [
 
1635
                ('parent', ' 100 78', (['tail', 'ghost'], )),
 
1636
                ('separate', '', ([], ))])
 
1637
        combined_index = CombinedGraphIndex([index1, index2])
 
1638
        if catch_adds:
 
1639
            self.combined_index = combined_index
 
1640
            self.caught_entries = []
 
1641
            add_callback = self.catch_add
 
1642
        else:
 
1643
            add_callback = None
 
1644
        return KnitGraphIndex(combined_index, deltas=deltas,
 
1645
            add_callback=add_callback)
 
1646
 
 
1647
    def test_get_graph(self):
 
1648
        index = self.two_graph_index()
 
1649
        self.assertEqual(set([
 
1650
            ('tip', ('parent', )),
 
1651
            ('tail', ()),
 
1652
            ('parent', ('tail', 'ghost')),
 
1653
            ('separate', ()),
 
1654
            ]), set(index.get_graph()))
 
1655
 
 
1656
    def test_get_ancestry(self):
 
1657
        # get_ancestry is defined as eliding ghosts, not erroring.
 
1658
        index = self.two_graph_index()
 
1659
        self.assertEqual([], index.get_ancestry([]))
 
1660
        self.assertEqual(['separate'], index.get_ancestry(['separate']))
 
1661
        self.assertEqual(['tail'], index.get_ancestry(['tail']))
 
1662
        self.assertEqual(['tail', 'parent'], index.get_ancestry(['parent']))
 
1663
        self.assertEqual(['tail', 'parent', 'tip'], index.get_ancestry(['tip']))
 
1664
        self.assertTrue(index.get_ancestry(['tip', 'separate']) in
 
1665
            (['tail', 'parent', 'tip', 'separate'],
 
1666
             ['separate', 'tail', 'parent', 'tip'],
 
1667
            ))
 
1668
        # and without topo_sort
 
1669
        self.assertEqual(set(['separate']),
 
1670
            set(index.get_ancestry(['separate'], topo_sorted=False)))
 
1671
        self.assertEqual(set(['tail']),
 
1672
            set(index.get_ancestry(['tail'], topo_sorted=False)))
 
1673
        self.assertEqual(set(['tail', 'parent']),
 
1674
            set(index.get_ancestry(['parent'], topo_sorted=False)))
 
1675
        self.assertEqual(set(['tail', 'parent', 'tip']),
 
1676
            set(index.get_ancestry(['tip'], topo_sorted=False)))
 
1677
        self.assertEqual(set(['separate', 'tail', 'parent', 'tip']),
 
1678
            set(index.get_ancestry(['tip', 'separate'])))
 
1679
        # asking for a ghost makes it go boom.
 
1680
        self.assertRaises(errors.RevisionNotPresent, index.get_ancestry, ['ghost'])
 
1681
 
 
1682
    def test_get_ancestry_with_ghosts(self):
 
1683
        index = self.two_graph_index()
 
1684
        self.assertEqual([], index.get_ancestry_with_ghosts([]))
 
1685
        self.assertEqual(['separate'], index.get_ancestry_with_ghosts(['separate']))
 
1686
        self.assertEqual(['tail'], index.get_ancestry_with_ghosts(['tail']))
 
1687
        self.assertTrue(index.get_ancestry_with_ghosts(['parent']) in
 
1688
            (['tail', 'ghost', 'parent'],
 
1689
             ['ghost', 'tail', 'parent'],
 
1690
            ))
 
1691
        self.assertTrue(index.get_ancestry_with_ghosts(['tip']) in
 
1692
            (['tail', 'ghost', 'parent', 'tip'],
 
1693
             ['ghost', 'tail', 'parent', 'tip'],
 
1694
            ))
 
1695
        self.assertTrue(index.get_ancestry_with_ghosts(['tip', 'separate']) in
 
1696
            (['tail', 'ghost', 'parent', 'tip', 'separate'],
 
1697
             ['ghost', 'tail', 'parent', 'tip', 'separate'],
 
1698
             ['separate', 'tail', 'ghost', 'parent', 'tip'],
 
1699
             ['separate', 'ghost', 'tail', 'parent', 'tip'],
 
1700
            ))
 
1701
        # asking for a ghost makes it go boom.
 
1702
        self.assertRaises(errors.RevisionNotPresent, index.get_ancestry_with_ghosts, ['ghost'])
 
1703
 
 
1704
    def test_num_versions(self):
 
1705
        index = self.two_graph_index()
 
1706
        self.assertEqual(4, index.num_versions())
 
1707
 
 
1708
    def test_get_versions(self):
 
1709
        index = self.two_graph_index()
 
1710
        self.assertEqual(set(['tail', 'tip', 'parent', 'separate']),
 
1711
            set(index.get_versions()))
 
1712
 
 
1713
    def test_has_version(self):
 
1714
        index = self.two_graph_index()
 
1715
        self.assertTrue(index.has_version('tail'))
 
1716
        self.assertFalse(index.has_version('ghost'))
 
1717
 
 
1718
    def test_get_position(self):
 
1719
        index = self.two_graph_index()
 
1720
        self.assertEqual((0, 100), index.get_position('tip'))
 
1721
        self.assertEqual((100, 78), index.get_position('parent'))
 
1722
 
 
1723
    def test_get_method_deltas(self):
 
1724
        index = self.two_graph_index(deltas=True)
 
1725
        self.assertEqual('fulltext', index.get_method('tip'))
 
1726
        self.assertEqual('line-delta', index.get_method('parent'))
 
1727
 
 
1728
    def test_get_method_no_deltas(self):
 
1729
        # check that the parent-history lookup is ignored with deltas=False.
 
1730
        index = self.two_graph_index(deltas=False)
 
1731
        self.assertEqual('fulltext', index.get_method('tip'))
 
1732
        self.assertEqual('fulltext', index.get_method('parent'))
 
1733
 
 
1734
    def test_get_options_deltas(self):
 
1735
        index = self.two_graph_index(deltas=True)
 
1736
        self.assertEqual('fulltext,no-eol', index.get_options('tip'))
 
1737
        self.assertEqual('line-delta', index.get_options('parent'))
 
1738
 
 
1739
    def test_get_options_no_deltas(self):
 
1740
        # check that the parent-history lookup is ignored with deltas=False.
 
1741
        index = self.two_graph_index(deltas=False)
 
1742
        self.assertEqual('fulltext,no-eol', index.get_options('tip'))
 
1743
        self.assertEqual('fulltext', index.get_options('parent'))
 
1744
 
 
1745
    def test_get_parents(self):
 
1746
        # get_parents ignores ghosts
 
1747
        index = self.two_graph_index()
 
1748
        self.assertEqual(('tail', ), index.get_parents('parent'))
 
1749
        # and errors on ghosts.
 
1750
        self.assertRaises(errors.RevisionNotPresent,
 
1751
            index.get_parents, 'ghost')
 
1752
 
 
1753
    def test_get_parents_with_ghosts(self):
 
1754
        index = self.two_graph_index()
 
1755
        self.assertEqual(('tail', 'ghost'), index.get_parents_with_ghosts('parent'))
 
1756
        # and errors on ghosts.
 
1757
        self.assertRaises(errors.RevisionNotPresent,
 
1758
            index.get_parents_with_ghosts, 'ghost')
 
1759
 
 
1760
    def test_check_versions_present(self):
 
1761
        # ghosts should not be considered present
 
1762
        index = self.two_graph_index()
 
1763
        self.assertRaises(RevisionNotPresent, index.check_versions_present,
 
1764
            ['ghost'])
 
1765
        self.assertRaises(RevisionNotPresent, index.check_versions_present,
 
1766
            ['tail', 'ghost'])
 
1767
        index.check_versions_present(['tail', 'separate'])
 
1768
 
 
1769
    def catch_add(self, entries):
 
1770
        self.caught_entries.append(entries)
 
1771
 
 
1772
    def test_add_no_callback_errors(self):
 
1773
        index = self.two_graph_index()
 
1774
        self.assertRaises(errors.ReadOnlyError, index.add_version,
 
1775
            'new', 'fulltext,no-eol', 50, 60, ['separate'])
 
1776
 
 
1777
    def test_add_version_smoke(self):
 
1778
        index = self.two_graph_index(catch_adds=True)
 
1779
        index.add_version('new', 'fulltext,no-eol', 50, 60, ['separate'])
 
1780
        self.assertEqual([[('new', 'N50 60', (('separate',),))]],
 
1781
            self.caught_entries)
 
1782
 
 
1783
    def test_add_version_delta_not_delta_index(self):
 
1784
        index = self.two_graph_index(catch_adds=True)
 
1785
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1786
            'new', 'no-eol,line-delta', 0, 100, ['parent'])
 
1787
        self.assertEqual([], self.caught_entries)
 
1788
 
 
1789
    def test_add_version_same_dup(self):
 
1790
        index = self.two_graph_index(catch_adds=True)
 
1791
        # options can be spelt two different ways
 
1792
        index.add_version('tip', 'fulltext,no-eol', 0, 100, ['parent'])
 
1793
        index.add_version('tip', 'no-eol,fulltext', 0, 100, ['parent'])
 
1794
        # but neither should have added data.
 
1795
        self.assertEqual([[], []], self.caught_entries)
 
1796
        
 
1797
    def test_add_version_different_dup(self):
 
1798
        index = self.two_graph_index(deltas=True, catch_adds=True)
 
1799
        # change options
 
1800
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1801
            'tip', 'no-eol,line-delta', 0, 100, ['parent'])
 
1802
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1803
            'tip', 'line-delta,no-eol', 0, 100, ['parent'])
 
1804
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1805
            'tip', 'fulltext', 0, 100, ['parent'])
 
1806
        # position/length
 
1807
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1808
            'tip', 'fulltext,no-eol', 50, 100, ['parent'])
 
1809
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1810
            'tip', 'fulltext,no-eol', 0, 1000, ['parent'])
 
1811
        # parents
 
1812
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
1813
            'tip', 'fulltext,no-eol', 0, 100, [])
 
1814
        self.assertEqual([], self.caught_entries)
 
1815
        
 
1816
    def test_add_versions_nodeltas(self):
 
1817
        index = self.two_graph_index(catch_adds=True)
 
1818
        index.add_versions([
 
1819
                ('new', 'fulltext,no-eol', 50, 60, ['separate']),
 
1820
                ('new2', 'fulltext', 0, 6, ['new']),
 
1821
                ])
 
1822
        self.assertEqual([('new', 'N50 60', (('separate',),)),
 
1823
            ('new2', ' 0 6', (('new',),))],
 
1824
            sorted(self.caught_entries[0]))
 
1825
        self.assertEqual(1, len(self.caught_entries))
 
1826
 
 
1827
    def test_add_versions_deltas(self):
 
1828
        index = self.two_graph_index(deltas=True, catch_adds=True)
 
1829
        index.add_versions([
 
1830
                ('new', 'fulltext,no-eol', 50, 60, ['separate']),
 
1831
                ('new2', 'line-delta', 0, 6, ['new']),
 
1832
                ])
 
1833
        self.assertEqual([('new', 'N50 60', (('separate',), ())),
 
1834
            ('new2', ' 0 6', (('new',), ('new',), ))],
 
1835
            sorted(self.caught_entries[0]))
 
1836
        self.assertEqual(1, len(self.caught_entries))
 
1837
 
 
1838
    def test_add_versions_delta_not_delta_index(self):
 
1839
        index = self.two_graph_index(catch_adds=True)
 
1840
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1841
            [('new', 'no-eol,line-delta', 0, 100, ['parent'])])
 
1842
        self.assertEqual([], self.caught_entries)
 
1843
 
 
1844
    def test_add_versions_same_dup(self):
 
1845
        index = self.two_graph_index(catch_adds=True)
 
1846
        # options can be spelt two different ways
 
1847
        index.add_versions([('tip', 'fulltext,no-eol', 0, 100, ['parent'])])
 
1848
        index.add_versions([('tip', 'no-eol,fulltext', 0, 100, ['parent'])])
 
1849
        # but neither should have added data.
 
1850
        self.assertEqual([[], []], self.caught_entries)
 
1851
        
 
1852
    def test_add_versions_different_dup(self):
 
1853
        index = self.two_graph_index(deltas=True, catch_adds=True)
 
1854
        # change options
 
1855
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1856
            [('tip', 'no-eol,line-delta', 0, 100, ['parent'])])
 
1857
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1858
            [('tip', 'line-delta,no-eol', 0, 100, ['parent'])])
 
1859
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1860
            [('tip', 'fulltext', 0, 100, ['parent'])])
 
1861
        # position/length
 
1862
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1863
            [('tip', 'fulltext,no-eol', 50, 100, ['parent'])])
 
1864
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1865
            [('tip', 'fulltext,no-eol', 0, 1000, ['parent'])])
 
1866
        # parents
 
1867
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1868
            [('tip', 'fulltext,no-eol', 0, 100, [])])
 
1869
        # change options in the second record
 
1870
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
1871
            [('tip', 'fulltext,no-eol', 0, 100, ['parent']),
 
1872
             ('tip', 'no-eol,line-delta', 0, 100, ['parent'])])
 
1873
        self.assertEqual([], self.caught_entries)
 
1874
 
 
1875
    def test_iter_parents(self):
 
1876
        index1 = self.make_g_index('1', 1, [
 
1877
        # no parents
 
1878
            ('r0', 'N0 100', ([], )),
 
1879
        # 1 parent
 
1880
            ('r1', '', (['r0'], ))])
 
1881
        index2 = self.make_g_index('2', 1, [
 
1882
        # 2 parents
 
1883
            ('r2', 'N0 100', (['r1', 'r0'], )),
 
1884
            ])
 
1885
        combined_index = CombinedGraphIndex([index1, index2])
 
1886
        index = KnitGraphIndex(combined_index)
 
1887
        # XXX TODO a ghost
 
1888
        # cases: each sample data individually:
 
1889
        self.assertEqual(set([('r0', ())]),
 
1890
            set(index.iter_parents(['r0'])))
 
1891
        self.assertEqual(set([('r1', ('r0', ))]),
 
1892
            set(index.iter_parents(['r1'])))
 
1893
        self.assertEqual(set([('r2', ('r1', 'r0'))]),
 
1894
            set(index.iter_parents(['r2'])))
 
1895
        # no nodes returned for a missing node
 
1896
        self.assertEqual(set(),
 
1897
            set(index.iter_parents(['missing'])))
 
1898
        # 1 node returned with missing nodes skipped
 
1899
        self.assertEqual(set([('r1', ('r0', ))]),
 
1900
            set(index.iter_parents(['ghost1', 'r1', 'ghost'])))
 
1901
        # 2 nodes returned
 
1902
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
 
1903
            set(index.iter_parents(['r0', 'r1'])))
 
1904
        # 2 nodes returned, missing skipped
 
1905
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
 
1906
            set(index.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))
 
1907
 
 
1908
 
 
1909
class TestNoParentsGraphIndexKnit(KnitTests):
 
1910
    """Tests for knits using KnitGraphIndex with no parents."""
 
1911
 
 
1912
    def make_g_index(self, name, ref_lists=0, nodes=[]):
 
1913
        builder = GraphIndexBuilder(ref_lists)
 
1914
        for node, references in nodes:
 
1915
            builder.add_node(node, references)
 
1916
        stream = builder.finish()
 
1917
        trans = self.get_transport()
 
1918
        trans.put_file(name, stream)
 
1919
        return GraphIndex(trans, name)
 
1920
 
 
1921
    def test_parents_deltas_incompatible(self):
 
1922
        index = CombinedGraphIndex([])
 
1923
        self.assertRaises(errors.KnitError, KnitGraphIndex, index,
 
1924
            deltas=True, parents=False)
 
1925
 
 
1926
    def two_graph_index(self, catch_adds=False):
 
1927
        """Build a two-graph index.
 
1928
 
 
1929
        :param deltas: If true, use underlying indices with two node-ref
 
1930
            lists and 'parent' set to a delta-compressed against tail.
 
1931
        """
 
1932
        # put several versions in the index.
 
1933
        index1 = self.make_g_index('1', 0, [
 
1934
            ('tip', 'N0 100'),
 
1935
            ('tail', '')])
 
1936
        index2 = self.make_g_index('2', 0, [
 
1937
            ('parent', ' 100 78'),
 
1938
            ('separate', '')])
 
1939
        combined_index = CombinedGraphIndex([index1, index2])
 
1940
        if catch_adds:
 
1941
            self.combined_index = combined_index
 
1942
            self.caught_entries = []
 
1943
            add_callback = self.catch_add
 
1944
        else:
 
1945
            add_callback = None
 
1946
        return KnitGraphIndex(combined_index, parents=False,
 
1947
            add_callback=add_callback)
 
1948
 
 
1949
    def test_get_graph(self):
 
1950
        index = self.two_graph_index()
 
1951
        self.assertEqual(set([
 
1952
            ('tip', ()),
 
1953
            ('tail', ()),
 
1954
            ('parent', ()),
 
1955
            ('separate', ()),
 
1956
            ]), set(index.get_graph()))
 
1957
 
 
1958
    def test_get_ancestry(self):
 
1959
        # with no parents, ancestry is always just the key.
 
1960
        index = self.two_graph_index()
 
1961
        self.assertEqual([], index.get_ancestry([]))
 
1962
        self.assertEqual(['separate'], index.get_ancestry(['separate']))
 
1963
        self.assertEqual(['tail'], index.get_ancestry(['tail']))
 
1964
        self.assertEqual(['parent'], index.get_ancestry(['parent']))
 
1965
        self.assertEqual(['tip'], index.get_ancestry(['tip']))
 
1966
        self.assertTrue(index.get_ancestry(['tip', 'separate']) in
 
1967
            (['tip', 'separate'],
 
1968
             ['separate', 'tip'],
 
1969
            ))
 
1970
        # asking for a ghost makes it go boom.
 
1971
        self.assertRaises(errors.RevisionNotPresent, index.get_ancestry, ['ghost'])
 
1972
 
 
1973
    def test_get_ancestry_with_ghosts(self):
 
1974
        index = self.two_graph_index()
 
1975
        self.assertEqual([], index.get_ancestry_with_ghosts([]))
 
1976
        self.assertEqual(['separate'], index.get_ancestry_with_ghosts(['separate']))
 
1977
        self.assertEqual(['tail'], index.get_ancestry_with_ghosts(['tail']))
 
1978
        self.assertEqual(['parent'], index.get_ancestry_with_ghosts(['parent']))
 
1979
        self.assertEqual(['tip'], index.get_ancestry_with_ghosts(['tip']))
 
1980
        self.assertTrue(index.get_ancestry_with_ghosts(['tip', 'separate']) in
 
1981
            (['tip', 'separate'],
 
1982
             ['separate', 'tip'],
 
1983
            ))
 
1984
        # asking for a ghost makes it go boom.
 
1985
        self.assertRaises(errors.RevisionNotPresent, index.get_ancestry_with_ghosts, ['ghost'])
 
1986
 
 
1987
    def test_num_versions(self):
 
1988
        index = self.two_graph_index()
 
1989
        self.assertEqual(4, index.num_versions())
 
1990
 
 
1991
    def test_get_versions(self):
 
1992
        index = self.two_graph_index()
 
1993
        self.assertEqual(set(['tail', 'tip', 'parent', 'separate']),
 
1994
            set(index.get_versions()))
 
1995
 
 
1996
    def test_has_version(self):
 
1997
        index = self.two_graph_index()
 
1998
        self.assertTrue(index.has_version('tail'))
 
1999
        self.assertFalse(index.has_version('ghost'))
 
2000
 
 
2001
    def test_get_position(self):
 
2002
        index = self.two_graph_index()
 
2003
        self.assertEqual((0, 100), index.get_position('tip'))
 
2004
        self.assertEqual((100, 78), index.get_position('parent'))
 
2005
 
 
2006
    def test_get_method(self):
 
2007
        index = self.two_graph_index()
 
2008
        self.assertEqual('fulltext', index.get_method('tip'))
 
2009
        self.assertEqual('fulltext', index.get_options('parent'))
 
2010
 
 
2011
    def test_get_options(self):
 
2012
        index = self.two_graph_index()
 
2013
        self.assertEqual('fulltext,no-eol', index.get_options('tip'))
 
2014
        self.assertEqual('fulltext', index.get_options('parent'))
 
2015
 
 
2016
    def test_get_parents(self):
 
2017
        index = self.two_graph_index()
 
2018
        self.assertEqual((), index.get_parents('parent'))
 
2019
        # and errors on ghosts.
 
2020
        self.assertRaises(errors.RevisionNotPresent,
 
2021
            index.get_parents, 'ghost')
 
2022
 
 
2023
    def test_get_parents_with_ghosts(self):
 
2024
        index = self.two_graph_index()
 
2025
        self.assertEqual((), index.get_parents_with_ghosts('parent'))
 
2026
        # and errors on ghosts.
 
2027
        self.assertRaises(errors.RevisionNotPresent,
 
2028
            index.get_parents_with_ghosts, 'ghost')
 
2029
 
 
2030
    def test_check_versions_present(self):
 
2031
        index = self.two_graph_index()
 
2032
        self.assertRaises(RevisionNotPresent, index.check_versions_present,
 
2033
            ['missing'])
 
2034
        self.assertRaises(RevisionNotPresent, index.check_versions_present,
 
2035
            ['tail', 'missing'])
 
2036
        index.check_versions_present(['tail', 'separate'])
 
2037
 
 
2038
    def catch_add(self, entries):
 
2039
        self.caught_entries.append(entries)
 
2040
 
 
2041
    def test_add_no_callback_errors(self):
 
2042
        index = self.two_graph_index()
 
2043
        self.assertRaises(errors.ReadOnlyError, index.add_version,
 
2044
            'new', 'fulltext,no-eol', 50, 60, ['separate'])
 
2045
 
 
2046
    def test_add_version_smoke(self):
 
2047
        index = self.two_graph_index(catch_adds=True)
 
2048
        index.add_version('new', 'fulltext,no-eol', 50, 60, [])
 
2049
        self.assertEqual([[('new', 'N50 60')]],
 
2050
            self.caught_entries)
 
2051
 
 
2052
    def test_add_version_delta_not_delta_index(self):
 
2053
        index = self.two_graph_index(catch_adds=True)
 
2054
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2055
            'new', 'no-eol,line-delta', 0, 100, [])
 
2056
        self.assertEqual([], self.caught_entries)
 
2057
 
 
2058
    def test_add_version_same_dup(self):
 
2059
        index = self.two_graph_index(catch_adds=True)
 
2060
        # options can be spelt two different ways
 
2061
        index.add_version('tip', 'fulltext,no-eol', 0, 100, [])
 
2062
        index.add_version('tip', 'no-eol,fulltext', 0, 100, [])
 
2063
        # but neither should have added data.
 
2064
        self.assertEqual([[], []], self.caught_entries)
 
2065
        
 
2066
    def test_add_version_different_dup(self):
 
2067
        index = self.two_graph_index(catch_adds=True)
 
2068
        # change options
 
2069
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2070
            'tip', 'no-eol,line-delta', 0, 100, [])
 
2071
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2072
            'tip', 'line-delta,no-eol', 0, 100, [])
 
2073
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2074
            'tip', 'fulltext', 0, 100, [])
 
2075
        # position/length
 
2076
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2077
            'tip', 'fulltext,no-eol', 50, 100, [])
 
2078
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2079
            'tip', 'fulltext,no-eol', 0, 1000, [])
 
2080
        # parents
 
2081
        self.assertRaises(errors.KnitCorrupt, index.add_version,
 
2082
            'tip', 'fulltext,no-eol', 0, 100, ['parent'])
 
2083
        self.assertEqual([], self.caught_entries)
 
2084
        
 
2085
    def test_add_versions(self):
 
2086
        index = self.two_graph_index(catch_adds=True)
 
2087
        index.add_versions([
 
2088
                ('new', 'fulltext,no-eol', 50, 60, []),
 
2089
                ('new2', 'fulltext', 0, 6, []),
 
2090
                ])
 
2091
        self.assertEqual([('new', 'N50 60'), ('new2', ' 0 6')],
 
2092
            sorted(self.caught_entries[0]))
 
2093
        self.assertEqual(1, len(self.caught_entries))
 
2094
 
 
2095
    def test_add_versions_delta_not_delta_index(self):
 
2096
        index = self.two_graph_index(catch_adds=True)
 
2097
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2098
            [('new', 'no-eol,line-delta', 0, 100, ['parent'])])
 
2099
        self.assertEqual([], self.caught_entries)
 
2100
 
 
2101
    def test_add_versions_parents_not_parents_index(self):
 
2102
        index = self.two_graph_index(catch_adds=True)
 
2103
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2104
            [('new', 'no-eol,fulltext', 0, 100, ['parent'])])
 
2105
        self.assertEqual([], self.caught_entries)
 
2106
 
 
2107
    def test_add_versions_same_dup(self):
 
2108
        index = self.two_graph_index(catch_adds=True)
 
2109
        # options can be spelt two different ways
 
2110
        index.add_versions([('tip', 'fulltext,no-eol', 0, 100, [])])
 
2111
        index.add_versions([('tip', 'no-eol,fulltext', 0, 100, [])])
 
2112
        # but neither should have added data.
 
2113
        self.assertEqual([[], []], self.caught_entries)
 
2114
        
 
2115
    def test_add_versions_different_dup(self):
 
2116
        index = self.two_graph_index(catch_adds=True)
 
2117
        # change options
 
2118
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2119
            [('tip', 'no-eol,line-delta', 0, 100, [])])
 
2120
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2121
            [('tip', 'line-delta,no-eol', 0, 100, [])])
 
2122
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2123
            [('tip', 'fulltext', 0, 100, [])])
 
2124
        # position/length
 
2125
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2126
            [('tip', 'fulltext,no-eol', 50, 100, [])])
 
2127
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2128
            [('tip', 'fulltext,no-eol', 0, 1000, [])])
 
2129
        # parents
 
2130
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2131
            [('tip', 'fulltext,no-eol', 0, 100, ['parent'])])
 
2132
        # change options in the second record
 
2133
        self.assertRaises(errors.KnitCorrupt, index.add_versions,
 
2134
            [('tip', 'fulltext,no-eol', 0, 100, []),
 
2135
             ('tip', 'no-eol,line-delta', 0, 100, [])])
 
2136
        self.assertEqual([], self.caught_entries)
 
2137
 
 
2138
    def test_iter_parents(self):
 
2139
        index = self.two_graph_index()
 
2140
        self.assertEqual(set([
 
2141
            ('tip', ()), ('tail', ()), ('parent', ()), ('separate', ())
 
2142
            ]),
 
2143
            set(index.iter_parents(['tip', 'tail', 'ghost', 'parent', 'separate'])))
 
2144
        self.assertEqual(set([('tip', ())]),
 
2145
            set(index.iter_parents(['tip'])))
 
2146
        self.assertEqual(set(),
 
2147
            set(index.iter_parents([])))