/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_knit.py

Merged bzr.dev r3374.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
from bzrlib.index import *
38
38
from bzrlib.knit import (
39
39
    AnnotatedKnitContent,
 
40
    DATA_SUFFIX,
 
41
    INDEX_SUFFIX,
40
42
    KnitContent,
41
43
    KnitGraphIndex,
42
44
    KnitVersionedFile,
45
47
    _KnitAccess,
46
48
    _KnitData,
47
49
    _KnitIndex,
 
50
    make_file_knit,
48
51
    _PackAccess,
49
52
    PlainKnitContent,
50
53
    _StreamAccess,
53
56
    KnitSequenceMatcher,
54
57
    )
55
58
from bzrlib.osutils import split_lines
 
59
from bzrlib.symbol_versioning import one_four
56
60
from bzrlib.tests import (
57
61
    Feature,
58
62
    TestCase,
158
162
        self.assertEqual(content.annotate(),
159
163
            [("bogus", "text1"), ("bogus", "text2")])
160
164
 
161
 
    def test_annotate_iter(self):
162
 
        content = self._make_content([])
163
 
        it = content.annotate_iter()
164
 
        self.assertRaises(StopIteration, it.next)
165
 
 
166
 
        content = self._make_content([("bogus", "text1"), ("bogus", "text2")])
167
 
        it = content.annotate_iter()
168
 
        self.assertEqual(it.next(), ("bogus", "text1"))
169
 
        self.assertEqual(it.next(), ("bogus", "text2"))
170
 
        self.assertRaises(StopIteration, it.next)
171
 
 
172
165
    def test_line_delta(self):
173
166
        content1 = self._make_content([("", "a"), ("", "b")])
174
167
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
196
189
        self.assertEqual(content.annotate(),
197
190
            [("origin1", "text1"), ("origin2", "text2")])
198
191
 
199
 
    def test_annotate_iter(self):
200
 
        content = self._make_content([])
201
 
        it = content.annotate_iter()
202
 
        self.assertRaises(StopIteration, it.next)
203
 
 
204
 
        content = self._make_content([("origin1", "text1"), ("origin2", "text2")])
205
 
        it = content.annotate_iter()
206
 
        self.assertEqual(it.next(), ("origin1", "text1"))
207
 
        self.assertEqual(it.next(), ("origin2", "text2"))
208
 
        self.assertRaises(StopIteration, it.next)
209
 
 
210
192
    def test_line_delta(self):
211
193
        content1 = self._make_content([("", "a"), ("", "b")])
212
194
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
492
474
        self.addCleanup(reset)
493
475
        from bzrlib._knit_load_data_py import _load_data_py
494
476
        knit._load_data = _load_data_py
495
 
        return _KnitIndex(*args, **kwargs)
 
477
        return _KnitIndex(get_scope=lambda:None, *args, **kwargs)
496
478
 
497
479
    def test_no_such_file(self):
498
480
        transport = MockTransport()
554
536
            "version option 0 1 .%s :" % (utf8_revision_id,)
555
537
            ])
556
538
        index = self.get_knit_index(transport, "filename", "r")
557
 
        self.assertEqual([utf8_revision_id],
 
539
        self.assertEqual((utf8_revision_id,),
558
540
            index.get_parents_with_ghosts("version"))
559
541
 
560
542
    def test_read_ignore_corrupted_lines(self):
588
570
        self.assertEqual("1", index._version_list_to_index(["version"]))
589
571
        self.assertEqual((None, 3, 4), index.get_position("version"))
590
572
        self.assertEqual(["options3"], index.get_options("version"))
591
 
        self.assertEqual(["parent", "other"],
 
573
        self.assertEqual(("parent", "other"),
592
574
            index.get_parents_with_ghosts("version"))
593
575
 
594
576
    def test_read_compressed_parents(self):
599
581
            "c option 0 1 1 0 :",
600
582
            ])
601
583
        index = self.get_knit_index(transport, "filename", "r")
602
 
        self.assertEqual(["a"], index.get_parents("b"))
603
 
        self.assertEqual(["b", "a"], index.get_parents("c"))
 
584
        self.assertEqual({"b":("a",), "c":("b", "a")},
 
585
            index.get_parent_map(["b", "c"]))
604
586
 
605
587
    def test_write_utf8_version_id(self):
606
588
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
628
610
            {}),
629
611
            transport.calls.pop(0))
630
612
 
631
 
    def test_get_graph(self):
632
 
        transport = MockTransport()
633
 
        index = self.get_knit_index(transport, "filename", "w", create=True)
634
 
        self.assertEqual([], index.get_graph())
635
 
 
636
 
        index.add_version("a", ["option"], (None, 0, 1), ["b"])
637
 
        self.assertEqual([("a", ["b"])], index.get_graph())
638
 
 
639
 
        index.add_version("c", ["option"], (None, 0, 1), ["d"])
640
 
        self.assertEqual([("a", ["b"]), ("c", ["d"])],
641
 
            sorted(index.get_graph()))
642
 
 
643
613
    def test_get_ancestry(self):
644
614
        transport = MockTransport([
645
615
            _KnitIndex.HEADER,
689
659
        self.assertRaises(RevisionNotPresent,
690
660
            index.get_ancestry_with_ghosts, ["e"])
691
661
 
692
 
    def test_iter_parents(self):
693
 
        transport = MockTransport()
694
 
        index = self.get_knit_index(transport, "filename", "w", create=True)
695
 
        # no parents
696
 
        index.add_version('r0', ['option'], (None, 0, 1), [])
697
 
        # 1 parent
698
 
        index.add_version('r1', ['option'], (None, 0, 1), ['r0'])
699
 
        # 2 parents
700
 
        index.add_version('r2', ['option'], (None, 0, 1), ['r1', 'r0'])
701
 
        # XXX TODO a ghost
702
 
        # cases: each sample data individually:
703
 
        self.assertEqual(set([('r0', ())]),
704
 
            set(index.iter_parents(['r0'])))
705
 
        self.assertEqual(set([('r1', ('r0', ))]),
706
 
            set(index.iter_parents(['r1'])))
707
 
        self.assertEqual(set([('r2', ('r1', 'r0'))]),
708
 
            set(index.iter_parents(['r2'])))
709
 
        # no nodes returned for a missing node
710
 
        self.assertEqual(set(),
711
 
            set(index.iter_parents(['missing'])))
712
 
        # 1 node returned with missing nodes skipped
713
 
        self.assertEqual(set([('r1', ('r0', ))]),
714
 
            set(index.iter_parents(['ghost1', 'r1', 'ghost'])))
715
 
        # 2 nodes returned
716
 
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
717
 
            set(index.iter_parents(['r0', 'r1'])))
718
 
        # 2 nodes returned, missing skipped
719
 
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
720
 
            set(index.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))
721
 
 
722
662
    def test_num_versions(self):
723
663
        transport = MockTransport([
724
664
            _KnitIndex.HEADER
771
711
        self.assertEqual(1, index.num_versions())
772
712
        self.assertEqual((None, 0, 1), index.get_position("a"))
773
713
        self.assertEqual(["option"], index.get_options("a"))
774
 
        self.assertEqual(["b"], index.get_parents_with_ghosts("a"))
 
714
        self.assertEqual(("b",), index.get_parents_with_ghosts("a"))
775
715
 
776
716
        index.add_version("a", ["opt"], (None, 1, 2), ["c"])
777
717
        self.assertEqual(("append_bytes",
781
721
        self.assertEqual(1, index.num_versions())
782
722
        self.assertEqual((None, 1, 2), index.get_position("a"))
783
723
        self.assertEqual(["opt"], index.get_options("a"))
784
 
        self.assertEqual(["c"], index.get_parents_with_ghosts("a"))
 
724
        self.assertEqual(("c",), index.get_parents_with_ghosts("a"))
785
725
 
786
726
        index.add_version("b", ["option"], (None, 2, 3), ["a"])
787
727
        self.assertEqual(("append_bytes",
791
731
        self.assertEqual(2, index.num_versions())
792
732
        self.assertEqual((None, 2, 3), index.get_position("b"))
793
733
        self.assertEqual(["option"], index.get_options("b"))
794
 
        self.assertEqual(["a"], index.get_parents_with_ghosts("b"))
 
734
        self.assertEqual(("a",), index.get_parents_with_ghosts("b"))
795
735
 
796
736
    def test_add_versions(self):
797
737
        transport = MockTransport([
816
756
        self.assertEqual((None, 2, 3), index.get_position("b"))
817
757
        self.assertEqual(["opt"], index.get_options("a"))
818
758
        self.assertEqual(["option"], index.get_options("b"))
819
 
        self.assertEqual(["c"], index.get_parents_with_ghosts("a"))
820
 
        self.assertEqual(["a"], index.get_parents_with_ghosts("b"))
 
759
        self.assertEqual(("c",), index.get_parents_with_ghosts("a"))
 
760
        self.assertEqual(("a",), index.get_parents_with_ghosts("b"))
821
761
 
822
762
    def test_add_versions_random_id_is_accepted(self):
823
763
        transport = MockTransport([
902
842
        self.assertEqual(["opt1"], index.get_options("a"))
903
843
        self.assertEqual(["opt2", "opt3"], index.get_options("b"))
904
844
 
905
 
    def test_get_parents(self):
 
845
    def test_get_parent_map(self):
906
846
        transport = MockTransport([
907
847
            _KnitIndex.HEADER,
908
848
            "a option 0 1 :",
911
851
            ])
912
852
        index = self.get_knit_index(transport, "filename", "r")
913
853
 
914
 
        self.assertEqual([], index.get_parents("a"))
915
 
        self.assertEqual(["a", "c"], index.get_parents("b"))
916
 
        self.assertEqual(["b", "a"], index.get_parents("c"))
 
854
        self.assertEqual({
 
855
            "a":(),
 
856
            "b":("a", "c"),
 
857
            "c":("b", "a", "e"),
 
858
            }, index.get_parent_map(["a", "b", "c"]))
917
859
 
918
860
    def test_get_parents_with_ghosts(self):
919
861
        transport = MockTransport([
924
866
            ])
925
867
        index = self.get_knit_index(transport, "filename", "r")
926
868
 
927
 
        self.assertEqual([], index.get_parents_with_ghosts("a"))
928
 
        self.assertEqual(["a", "c"], index.get_parents_with_ghosts("b"))
929
 
        self.assertEqual(["b", "a", "e"],
 
869
        self.assertEqual((), index.get_parents_with_ghosts("a"))
 
870
        self.assertEqual(("a", "c"), index.get_parents_with_ghosts("b"))
 
871
        self.assertEqual(("b", "a", "e"),
930
872
            index.get_parents_with_ghosts("c"))
931
873
 
932
874
    def test_check_versions_present(self):
1085
1027
        self.addCleanup(reset)
1086
1028
        from bzrlib._knit_load_data_c import _load_data_c
1087
1029
        knit._load_data = _load_data_c
1088
 
        return _KnitIndex(*args, **kwargs)
1089
 
 
 
1030
        return _KnitIndex(get_scope=lambda:None, *args, **kwargs)
1090
1031
 
1091
1032
 
1092
1033
class KnitTests(TestCaseWithTransport):
1093
1034
    """Class containing knit test helper routines."""
1094
1035
 
1095
1036
    def make_test_knit(self, annotate=False, delay_create=False, index=None,
1096
 
                       name='test'):
 
1037
                       name='test', delta=True, access_mode='w'):
1097
1038
        if not annotate:
1098
1039
            factory = KnitPlainFactory()
1099
1040
        else:
1100
1041
            factory = None
1101
 
        return KnitVersionedFile(name, get_transport('.'), access_mode='w',
1102
 
                                 factory=factory, create=True,
1103
 
                                 delay_create=delay_create, index=index)
 
1042
        if index is None:
 
1043
            index = _KnitIndex(get_transport('.'), name + INDEX_SUFFIX,
 
1044
                access_mode, create=True, file_mode=None,
 
1045
                create_parent_dir=False, delay_create=delay_create,
 
1046
                dir_mode=None, get_scope=lambda:None)
 
1047
        access = _KnitAccess(get_transport('.'), name + DATA_SUFFIX, None,
 
1048
            None, delay_create, False)
 
1049
        return KnitVersionedFile(name, get_transport('.'), factory=factory,
 
1050
            create=True, delay_create=delay_create, index=index,
 
1051
            access_method=access, delta=delta)
1104
1052
 
1105
1053
    def assertRecordContentEqual(self, knit, version_id, candidate_content):
1106
1054
        """Assert that some raw record content matches the raw record content
1125
1073
    def test_make_explicit_index(self):
1126
1074
        """We can supply an index to use."""
1127
1075
        knit = KnitVersionedFile('test', get_transport('.'),
1128
 
            index='strangelove')
 
1076
            index='strangelove', access_method="a")
1129
1077
        self.assertEqual(knit._index, 'strangelove')
1130
1078
 
1131
1079
    def test_knit_add(self):
1172
1120
        k = self.make_test_knit()
1173
1121
        k.add_lines('text-1', [], split_lines(TEXT_1))
1174
1122
        del k
1175
 
        k2 = KnitVersionedFile('test', get_transport('.'), access_mode='r', factory=KnitPlainFactory(), create=True)
 
1123
        k2 = make_file_knit('test', get_transport('.'), access_mode='r',
 
1124
            factory=KnitPlainFactory(), create=True)
1176
1125
        self.assertTrue(k2.has_version('text-1'))
1177
1126
        self.assertEqualDiff(''.join(k2.get_lines('text-1')), TEXT_1)
1178
1127
 
1200
1149
    def test_incomplete(self):
1201
1150
        """Test if texts without a ending line-end can be inserted and
1202
1151
        extracted."""
1203
 
        k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True)
 
1152
        k = make_file_knit('test', get_transport('.'), delta=False, create=True)
1204
1153
        k.add_lines('text-1', [], ['a\n',    'b'  ])
1205
1154
        k.add_lines('text-2', ['text-1'], ['a\rb\n', 'b\n'])
1206
1155
        # reopening ensures maximum room for confusion
1207
 
        k = KnitVersionedFile('test', get_transport('.'), delta=False, create=True)
 
1156
        k = make_file_knit('test', get_transport('.'), delta=False, create=True)
1208
1157
        self.assertEquals(k.get_lines('text-1'), ['a\n',    'b'  ])
1209
1158
        self.assertEquals(k.get_lines('text-2'), ['a\rb\n', 'b\n'])
1210
1159
 
1221
1170
        """Store in knit with parents"""
1222
1171
        k = self.make_test_knit()
1223
1172
        self.add_stock_one_and_one_a(k)
1224
 
        self.assertEquals(k.get_parents('text-1'), [])
1225
 
        self.assertEquals(k.get_parents('text-1a'), ['text-1'])
 
1173
        self.assertEqual({'text-1':(), 'text-1a':('text-1',)},
 
1174
            k.get_parent_map(['text-1', 'text-1a']))
1226
1175
 
1227
1176
    def test_ancestry(self):
1228
1177
        """Store in knit with parents"""
1232
1181
 
1233
1182
    def test_add_delta(self):
1234
1183
        """Store in knit with parents"""
1235
 
        k = KnitVersionedFile('test', get_transport('.'), factory=KnitPlainFactory(),
1236
 
            delta=True, create=True)
 
1184
        k = self.make_test_knit(annotate=False)
1237
1185
        self.add_stock_one_and_one_a(k)
1238
 
        k.clear_cache()
1239
1186
        self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A)
1240
1187
 
1241
1188
    def test_add_delta_knit_graph_index(self):
1243
1190
        index = InMemoryGraphIndex(2)
1244
1191
        knit_index = KnitGraphIndex(index, add_callback=index.add_nodes,
1245
1192
            deltas=True)
1246
 
        k = KnitVersionedFile('test', get_transport('.'),
1247
 
            delta=True, create=True, index=knit_index)
 
1193
        k = self.make_test_knit(annotate=True, index=knit_index)
1248
1194
        self.add_stock_one_and_one_a(k)
1249
 
        k.clear_cache()
1250
1195
        self.assertEqualDiff(''.join(k.get_lines('text-1a')), TEXT_1A)
1251
1196
        # check the index had the right data added.
1252
1197
        self.assertEqual(set([
1258
1203
 
1259
1204
    def test_annotate(self):
1260
1205
        """Annotations"""
1261
 
        k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(),
1262
 
            delta=True, create=True)
 
1206
        k = self.make_test_knit(annotate=True, name='knit')
1263
1207
        self.insert_and_test_small_annotate(k)
1264
1208
 
1265
1209
    def insert_and_test_small_annotate(self, k):
1273
1217
 
1274
1218
    def test_annotate_fulltext(self):
1275
1219
        """Annotations"""
1276
 
        k = KnitVersionedFile('knit', get_transport('.'), factory=KnitAnnotateFactory(),
1277
 
            delta=False, create=True)
 
1220
        k = self.make_test_knit(annotate=True, name='knit', delta=False)
1278
1221
        self.insert_and_test_small_annotate(k)
1279
1222
 
1280
1223
    def test_annotate_merge_1(self):
1351
1294
        self.assertEquals(origins[2], ('text-1', 'c\n'))
1352
1295
 
1353
1296
    def _test_join_with_factories(self, k1_factory, k2_factory):
1354
 
        k1 = KnitVersionedFile('test1', get_transport('.'), factory=k1_factory, create=True)
 
1297
        k1 = make_file_knit('test1', get_transport('.'), factory=k1_factory, create=True)
1355
1298
        k1.add_lines('text-a', [], ['a1\n', 'a2\n', 'a3\n'])
1356
1299
        k1.add_lines('text-b', ['text-a'], ['a1\n', 'b2\n', 'a3\n'])
1357
1300
        k1.add_lines('text-c', [], ['c1\n', 'c2\n', 'c3\n'])
1358
1301
        k1.add_lines('text-d', ['text-c'], ['c1\n', 'd2\n', 'd3\n'])
1359
1302
        k1.add_lines('text-m', ['text-b', 'text-d'], ['a1\n', 'b2\n', 'd3\n'])
1360
 
        k2 = KnitVersionedFile('test2', get_transport('.'), factory=k2_factory, create=True)
 
1303
        k2 = make_file_knit('test2', get_transport('.'), factory=k2_factory, create=True)
1361
1304
        count = k2.join(k1, version_ids=['text-m'])
1362
1305
        self.assertEquals(count, 5)
1363
1306
        self.assertTrue(k2.has_version('text-a'))
1384
1327
        self._test_join_with_factories(KnitPlainFactory(), None)
1385
1328
 
1386
1329
    def test_reannotate(self):
1387
 
        k1 = KnitVersionedFile('knit1', get_transport('.'),
 
1330
        k1 = make_file_knit('knit1', get_transport('.'),
1388
1331
                               factory=KnitAnnotateFactory(), create=True)
1389
1332
        # 0
1390
1333
        k1.add_lines('text-a', [], ['a\n', 'b\n'])
1391
1334
        # 1
1392
1335
        k1.add_lines('text-b', ['text-a'], ['a\n', 'c\n'])
1393
1336
 
1394
 
        k2 = KnitVersionedFile('test2', get_transport('.'),
 
1337
        k2 = make_file_knit('test2', get_transport('.'),
1395
1338
                               factory=KnitAnnotateFactory(), create=True)
1396
1339
        k2.join(k1, version_ids=['text-b'])
1397
1340
 
1414
1357
 
1415
1358
    def test_get_line_delta_texts(self):
1416
1359
        """Make sure we can call get_texts on text with reused line deltas"""
1417
 
        k1 = KnitVersionedFile('test1', get_transport('.'), 
1418
 
                               factory=KnitPlainFactory(), create=True)
 
1360
        k1 = make_file_knit('test1', get_transport('.'),
 
1361
            factory=KnitPlainFactory(), create=True)
1419
1362
        for t in range(3):
1420
1363
            if t == 0:
1421
1364
                parents = []
1426
1369
        
1427
1370
    def test_iter_lines_reads_in_order(self):
1428
1371
        instrumented_t = get_transport('trace+memory:///')
1429
 
        k1 = KnitVersionedFile('id', instrumented_t, create=True, delta=True)
 
1372
        k1 = make_file_knit('id', instrumented_t, create=True, delta=True)
1430
1373
        self.assertEqual([('get', 'id.kndx',)], instrumented_t._activity)
1431
1374
        # add texts with no required ordering
1432
1375
        k1.add_lines('base', [], ['text\n'])
1433
1376
        k1.add_lines('base2', [], ['text2\n'])
1434
 
        k1.clear_cache()
1435
1377
        # clear the logged activity, but preserve the list instance in case of
1436
1378
        # clones pointing at it.
1437
1379
        del instrumented_t._activity[:]
1443
1385
            instrumented_t._activity)
1444
1386
        self.assertEqual([('text\n', 'base'), ('text2\n', 'base2')], results)
1445
1387
 
1446
 
    def test_create_empty_annotated(self):
1447
 
        k1 = self.make_test_knit(True)
1448
 
        # 0
1449
 
        k1.add_lines('text-a', [], ['a\n', 'b\n'])
1450
 
        k2 = k1.create_empty('t', MemoryTransport())
1451
 
        self.assertTrue(isinstance(k2.factory, KnitAnnotateFactory))
1452
 
        self.assertEqual(k1.delta, k2.delta)
1453
 
        # the generic test checks for empty content and file class
1454
 
 
1455
1388
    def test_knit_format(self):
1456
1389
        # this tests that a new knit index file has the expected content
1457
1390
        # and that is writes the data we expect as records are added.
1471
1404
            "\nrevid2 line-delta 84 82 0 :",
1472
1405
            'test.kndx')
1473
1406
        # we should be able to load this file again
1474
 
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='r')
 
1407
        knit = make_file_knit('test', get_transport('.'), access_mode='r')
1475
1408
        self.assertEqual(['revid', 'revid2'], knit.versions())
1476
1409
        # write a short write to the file and ensure that its ignored
1477
1410
        indexfile = file('test.kndx', 'ab')
1478
1411
        indexfile.write('\nrevid3 line-delta 166 82 1 2 3 4 5 .phwoar:demo ')
1479
1412
        indexfile.close()
1480
1413
        # we should be able to load this file again
1481
 
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='w')
 
1414
        knit = make_file_knit('test', get_transport('.'), access_mode='w')
1482
1415
        self.assertEqual(['revid', 'revid2'], knit.versions())
1483
1416
        # and add a revision with the same id the failed write had
1484
1417
        knit.add_lines('revid3', ['revid2'], ['a\n'])
1485
1418
        # and when reading it revid3 should now appear.
1486
 
        knit = KnitVersionedFile('test', get_transport('.'), access_mode='r')
 
1419
        knit = make_file_knit('test', get_transport('.'), access_mode='r')
1487
1420
        self.assertEqual(['revid', 'revid2', 'revid3'], knit.versions())
1488
 
        self.assertEqual(['revid2'], knit.get_parents('revid3'))
 
1421
        self.assertEqual({'revid3':('revid2',)}, knit.get_parent_map(['revid3']))
1489
1422
 
1490
1423
    def test_delay_create(self):
1491
1424
        """Test that passing delay_create=True creates files late"""
1504
1437
        """create_parent_dir can create knits in nonexistant dirs"""
1505
1438
        # Has no effect if we don't set 'delay_create'
1506
1439
        trans = get_transport('.')
1507
 
        self.assertRaises(NoSuchFile, KnitVersionedFile, 'dir/test',
 
1440
        self.assertRaises(NoSuchFile, make_file_knit, 'dir/test',
1508
1441
                          trans, access_mode='w', factory=None,
1509
1442
                          create=True, create_parent_dir=True)
1510
1443
        # Nothing should have changed yet
1511
 
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
 
1444
        knit = make_file_knit('dir/test', trans, access_mode='w',
1512
1445
                                 factory=None, create=True,
1513
1446
                                 create_parent_dir=True,
1514
1447
                                 delay_create=True)
1529
1462
        if not trans._can_roundtrip_unix_modebits():
1530
1463
            # Can't roundtrip, so no need to run this test
1531
1464
            return
1532
 
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
1533
 
                                 factory=None, create=True,
1534
 
                                 create_parent_dir=True,
1535
 
                                 delay_create=True,
1536
 
                                 file_mode=0600,
1537
 
                                 dir_mode=0700)
 
1465
        knit = make_file_knit('dir/test', trans, access_mode='w', factory=None,
 
1466
            create=True, create_parent_dir=True, delay_create=True,
 
1467
            file_mode=0600, dir_mode=0700)
1538
1468
        knit.add_lines('revid', [], ['a\n'])
1539
1469
        self.assertTransportMode(trans, 'dir', 0700)
1540
1470
        self.assertTransportMode(trans, 'dir/test.knit', 0600)
1545
1475
        if not trans._can_roundtrip_unix_modebits():
1546
1476
            # Can't roundtrip, so no need to run this test
1547
1477
            return
1548
 
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
1549
 
                                 factory=None, create=True,
1550
 
                                 create_parent_dir=True,
1551
 
                                 delay_create=True,
1552
 
                                 file_mode=0660,
1553
 
                                 dir_mode=0770)
 
1478
        knit = make_file_knit('dir/test', trans, access_mode='w', factory=None,
 
1479
            create=True, create_parent_dir=True, delay_create=True,
 
1480
            file_mode=0660, dir_mode=0770)
1554
1481
        knit.add_lines('revid', [], ['a\n'])
1555
1482
        self.assertTransportMode(trans, 'dir', 0770)
1556
1483
        self.assertTransportMode(trans, 'dir/test.knit', 0660)
1561
1488
        if not trans._can_roundtrip_unix_modebits():
1562
1489
            # Can't roundtrip, so no need to run this test
1563
1490
            return
1564
 
        knit = KnitVersionedFile('dir/test', trans, access_mode='w',
1565
 
                                 factory=None, create=True,
1566
 
                                 create_parent_dir=True,
1567
 
                                 delay_create=True,
1568
 
                                 file_mode=0666,
1569
 
                                 dir_mode=0777)
 
1491
        knit = make_file_knit('dir/test', trans, access_mode='w', factory=None,
 
1492
            create=True, create_parent_dir=True, delay_create=True,
 
1493
            file_mode=0666, dir_mode=0777)
1570
1494
        knit.add_lines('revid', [], ['a\n'])
1571
1495
        self.assertTransportMode(trans, 'dir', 0777)
1572
1496
        self.assertTransportMode(trans, 'dir/test.knit', 0666)
1601
1525
            ]
1602
1526
        expected_data_list = [
1603
1527
            # version, options, length, parents
1604
 
            ('text-a', ['fulltext'], 122, []),
 
1528
            ('text-a', ['fulltext'], 122, ()),
1605
1529
           ]
1606
1530
        for version_id, parents, lines in test_data:
1607
1531
            k1.add_lines(version_id, parents, split_lines(lines))
1630
1554
            ]
1631
1555
        expected_data_list = [
1632
1556
            # version, options, length, parents
1633
 
            ('text-m', ['line-delta'], 84, ['text-b', 'text-d']),
 
1557
            ('text-m', ['line-delta'], 84, ('text-b', 'text-d')),
1634
1558
            ]
1635
1559
        for version_id, parents, lines in test_data:
1636
1560
            k1.add_lines(version_id, parents, split_lines(lines))
1660
1584
        original_versions = k1.versions
1661
1585
        k1.versions = lambda: reversed(original_versions())
1662
1586
        expected_data_list = [
1663
 
            ('text-a', ['fulltext'], 122, []),
1664
 
            ('text-b', ['line-delta'], 84, ['text-a'])]
 
1587
            ('text-a', ['fulltext'], 122, ()),
 
1588
            ('text-b', ['line-delta'], 84, ('text-a',))]
1665
1589
        # now check the fulltext is first and the delta second
1666
1590
        format, data_list, _ = k1.get_data_stream(['text-a', 'text-b'])
1667
1591
        self.assertEqual('knit-plain', format)
1673
1597
        format, data_list, _ = k1.get_data_stream([
1674
1598
            'text-m', 'text-b', 'text-a'])
1675
1599
        self.assertEqual([
1676
 
            ('text-a', ['fulltext'], 122, []),
1677
 
            ('text-b', ['line-delta'], 84, ['text-a']),
1678
 
            ('text-m', ['line-delta'], 84, ['text-b', 'text-d']),
 
1600
            ('text-a', ['fulltext'], 122, ()),
 
1601
            ('text-b', ['line-delta'], 84, ('text-a',)),
 
1602
            ('text-m', ['line-delta'], 84, ('text-b', 'text-d')),
1679
1603
            ], data_list)
1680
1604
 
1681
1605
    def test_get_stream_ghost_parent(self):
1688
1612
        # Expected data
1689
1613
        expected_data_list = [
1690
1614
            # version, options, length, parents
1691
 
            ('text-b', ['line-delta'], 84, ['text-a', 'text-ghost']),
 
1615
            ('text-b', ['line-delta'], 84, ('text-a', 'text-ghost')),
1692
1616
            ]
1693
1617
        
1694
1618
        format, data_list, reader_callable = k1.get_data_stream(['text-b'])
1716
1640
        # behaviour.
1717
1641
        expected_data_list = [
1718
1642
            # version, options, length, parents
1719
 
            ('text-d', ['line-delta'], 84, ['text-c']),
1720
 
            ('text-b', ['line-delta'], 84, ['text-a']),
 
1643
            ('text-d', ['line-delta'], 84, ('text-c',)),
 
1644
            ('text-b', ['line-delta'], 84, ('text-a',)),
1721
1645
            ]
1722
1646
        # Note that even though we request the revision IDs in a particular
1723
1647
        # order, the data stream may return them in any order it likes.  In this
1758
1682
        # behaviour.
1759
1683
        expected_data_list = [
1760
1684
            # version, options, length, parents
1761
 
            ('text-a', ['fulltext'], 122, []),
1762
 
            ('text-b', ['line-delta'], 84, ['text-a']),
1763
 
            ('text-m', ['line-delta'], 84, ['text-b', 'text-d']),
1764
 
            ('text-c', ['fulltext'], 121, []),
1765
 
            ('text-d', ['line-delta'], 84, ['text-c']),
 
1685
            ('text-a', ['fulltext'], 122, ()),
 
1686
            ('text-b', ['line-delta'], 84, ('text-a',)),
 
1687
            ('text-m', ['line-delta'], 84, ('text-b', 'text-d')),
 
1688
            ('text-c', ['fulltext'], 121, ()),
 
1689
            ('text-d', ['line-delta'], 84, ('text-c',)),
1766
1690
            ]
1767
1691
        format, data_list, reader_callable = k1.get_data_stream(
1768
1692
            ['text-a', 'text-b', 'text-c', 'text-d', 'text-m'])
1895
1819
        # The target knit object is in a consistent state, i.e. the record we
1896
1820
        # just added is immediately visible.
1897
1821
        self.assertTrue(target.has_version('text-a'))
1898
 
        self.assertTrue(target.has_ghost('text-ghost'))
 
1822
        self.assertFalse(target.has_version('text-ghost'))
 
1823
        self.assertEqual({'text-a':('text-ghost',)},
 
1824
            target.get_parent_map(['text-a', 'text-ghost']))
1899
1825
        self.assertEqual(split_lines(TEXT_1), target.get_lines('text-a'))
1900
1826
 
1901
1827
    def test_insert_data_stream_inconsistent_version_lines(self):
1941
1867
            errors.KnitDataStreamUnknown,
1942
1868
            target.insert_data_stream, data_stream)
1943
1869
 
 
1870
    def test_insert_data_stream_bug_208418(self):
 
1871
        """You can insert a stream with an incompatible format, even when:
 
1872
          * the stream has a line-delta record,
 
1873
          * whose parent is in the target, also stored as a line-delta
 
1874
 
 
1875
        See <https://launchpad.net/bugs/208418>.
 
1876
        """
 
1877
        base_lines = split_lines(TEXT_1)
 
1878
        # Make the target
 
1879
        target = self.make_test_knit(name='target', annotate=True)
 
1880
        target.add_lines('version-1', [], base_lines)
 
1881
        target.add_lines('version-2', ['version-1'], base_lines + ['a\n'])
 
1882
        # The second record should be a delta.
 
1883
        self.assertEqual('line-delta', target._index.get_method('version-2'))
 
1884
        
 
1885
        # Make a source, with a different format, but the same data
 
1886
        source = self.make_test_knit(name='source', annotate=False)
 
1887
        source.add_lines('version-1', [], base_lines)
 
1888
        source.add_lines('version-2', ['version-1'], base_lines + ['a\n'])
 
1889
        # Now add another record, which should be stored as a delta against
 
1890
        # version-2.
 
1891
        source.add_lines('version-3', ['version-2'], base_lines + ['b\n'])
 
1892
        self.assertEqual('line-delta', source._index.get_method('version-3'))
 
1893
 
 
1894
        # Make a stream of the new version
 
1895
        data_stream = source.get_data_stream(['version-3'])
 
1896
        # And insert into the target
 
1897
        target.insert_data_stream(data_stream)
 
1898
        # No errors should have been raised.
 
1899
 
 
1900
 
1944
1901
    #  * test that a stream of "already present version, then new version"
1945
1902
    #    inserts correctly.
1946
1903
 
2073
2030
    def test_weave_to_knit_matches(self):
2074
2031
        # check that the WeaveToKnit is_compatible function
2075
2032
        # registers True for a Weave to a Knit.
2076
 
        w = Weave()
 
2033
        w = Weave(get_scope=lambda:None)
2077
2034
        k = self.make_test_knit()
2078
2035
        self.failUnless(WeaveToKnit.is_compatible(w, k))
2079
2036
        self.failIf(WeaveToKnit.is_compatible(k, w))
2081
2038
        self.failIf(WeaveToKnit.is_compatible(k, k))
2082
2039
 
2083
2040
 
2084
 
class TestKnitCaching(KnitTests):
2085
 
    
2086
 
    def create_knit(self):
2087
 
        k = self.make_test_knit(True)
2088
 
        k.add_lines('text-1', [], split_lines(TEXT_1))
2089
 
        k.add_lines('text-2', [], split_lines(TEXT_2))
2090
 
        return k
2091
 
 
2092
 
    def test_no_caching(self):
2093
 
        k = self.create_knit()
2094
 
        # Nothing should be cached without setting 'enable_cache'
2095
 
        self.assertEqual({}, k._data._cache)
2096
 
 
2097
 
    def test_cache_data_read_raw(self):
2098
 
        k = self.create_knit()
2099
 
 
2100
 
        # Now cache and read
2101
 
        k.enable_cache()
2102
 
 
2103
 
        def read_one_raw(version):
2104
 
            pos_map = k._get_components_positions([version])
2105
 
            method, index_memo, next = pos_map[version]
2106
 
            lst = list(k._data.read_records_iter_raw([(version, index_memo)]))
2107
 
            self.assertEqual(1, len(lst))
2108
 
            return lst[0]
2109
 
 
2110
 
        val = read_one_raw('text-1')
2111
 
        self.assertEqual({'text-1':val[1]}, k._data._cache)
2112
 
 
2113
 
        k.clear_cache()
2114
 
        # After clear, new reads are not cached
2115
 
        self.assertEqual({}, k._data._cache)
2116
 
 
2117
 
        val2 = read_one_raw('text-1')
2118
 
        self.assertEqual(val, val2)
2119
 
        self.assertEqual({}, k._data._cache)
2120
 
 
2121
 
    def test_cache_data_read(self):
2122
 
        k = self.create_knit()
2123
 
 
2124
 
        def read_one(version):
2125
 
            pos_map = k._get_components_positions([version])
2126
 
            method, index_memo, next = pos_map[version]
2127
 
            lst = list(k._data.read_records_iter([(version, index_memo)]))
2128
 
            self.assertEqual(1, len(lst))
2129
 
            return lst[0]
2130
 
 
2131
 
        # Now cache and read
2132
 
        k.enable_cache()
2133
 
 
2134
 
        val = read_one('text-2')
2135
 
        self.assertEqual(['text-2'], k._data._cache.keys())
2136
 
        self.assertEqual('text-2', val[0])
2137
 
        content, digest = k._data._parse_record('text-2',
2138
 
                                                k._data._cache['text-2'])
2139
 
        self.assertEqual(content, val[1])
2140
 
        self.assertEqual(digest, val[2])
2141
 
 
2142
 
        k.clear_cache()
2143
 
        self.assertEqual({}, k._data._cache)
2144
 
 
2145
 
        val2 = read_one('text-2')
2146
 
        self.assertEqual(val, val2)
2147
 
        self.assertEqual({}, k._data._cache)
2148
 
 
2149
 
    def test_cache_read(self):
2150
 
        k = self.create_knit()
2151
 
        k.enable_cache()
2152
 
 
2153
 
        text = k.get_text('text-1')
2154
 
        self.assertEqual(TEXT_1, text)
2155
 
        self.assertEqual(['text-1'], k._data._cache.keys())
2156
 
 
2157
 
        k.clear_cache()
2158
 
        self.assertEqual({}, k._data._cache)
2159
 
 
2160
 
        text = k.get_text('text-1')
2161
 
        self.assertEqual(TEXT_1, text)
2162
 
        self.assertEqual({}, k._data._cache)
2163
 
 
2164
 
 
2165
2041
class TestKnitIndex(KnitTests):
2166
2042
 
2167
2043
    def test_add_versions_dictionary_compresses(self):
2185
2061
            'a-3 fulltext 0 0 1 :'
2186
2062
            )
2187
2063
        self.assertEqual(['a-1', 'a-2', 'a-3'], idx._history)
2188
 
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0),
2189
 
                          'a-2':('a-2', ['fulltext'], 0, 0, ['a-1'], 1),
2190
 
                          'a-3':('a-3', ['fulltext'], 0, 0, ['a-2'], 2),
 
2064
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, (), 0),
 
2065
                          'a-2':('a-2', ['fulltext'], 0, 0, ('a-1',), 1),
 
2066
                          'a-3':('a-3', ['fulltext'], 0, 0, ('a-2',), 2),
2191
2067
                         }, idx._cache)
2192
2068
 
2193
2069
    def test_add_versions_fails_clean(self):
2211
2087
 
2212
2088
        def generate_failure():
2213
2089
            """Add some entries and then raise an exception"""
2214
 
            yield ('a-2', ['fulltext'], (None, 0, 0), ['a-1'])
2215
 
            yield ('a-3', ['fulltext'], (None, 0, 0), ['a-2'])
 
2090
            yield ('a-2', ['fulltext'], (None, 0, 0), ('a-1',))
 
2091
            yield ('a-3', ['fulltext'], (None, 0, 0), ('a-2',))
2216
2092
            raise StopEarly()
2217
2093
 
2218
2094
        # Assert the pre-condition
2219
2095
        self.assertEqual(['a-1'], idx._history)
2220
 
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0)}, idx._cache)
 
2096
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, (), 0)}, idx._cache)
2221
2097
 
2222
2098
        self.assertRaises(StopEarly, idx.add_versions, generate_failure())
2223
2099
 
2224
2100
        # And it shouldn't be modified
2225
2101
        self.assertEqual(['a-1'], idx._history)
2226
 
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, [], 0)}, idx._cache)
 
2102
        self.assertEqual({'a-1':('a-1', ['fulltext'], 0, 0, (), 0)}, idx._cache)
2227
2103
 
2228
2104
    def test_knit_index_ignores_empty_files(self):
2229
2105
        # There was a race condition in older bzr, where a ^C at the right time
2287
2163
        return KnitGraphIndex(combined_index, deltas=deltas,
2288
2164
            add_callback=add_callback)
2289
2165
 
2290
 
    def test_get_graph(self):
2291
 
        index = self.two_graph_index()
2292
 
        self.assertEqual(set([
2293
 
            ('tip', ('parent', )),
2294
 
            ('tail', ()),
2295
 
            ('parent', ('tail', 'ghost')),
2296
 
            ('separate', ()),
2297
 
            ]), set(index.get_graph()))
2298
 
 
2299
2166
    def test_get_ancestry(self):
2300
2167
        # get_ancestry is defined as eliding ghosts, not erroring.
2301
2168
        index = self.two_graph_index()
2385
2252
        self.assertEqual(['fulltext', 'no-eol'], index.get_options('tip'))
2386
2253
        self.assertEqual(['fulltext'], index.get_options('parent'))
2387
2254
 
2388
 
    def test_get_parents(self):
2389
 
        # get_parents ignores ghosts
2390
 
        index = self.two_graph_index()
2391
 
        self.assertEqual(('tail', ), index.get_parents('parent'))
2392
 
        # and errors on ghosts.
2393
 
        self.assertRaises(errors.RevisionNotPresent,
2394
 
            index.get_parents, 'ghost')
2395
 
 
2396
2255
    def test_get_parents_with_ghosts(self):
2397
2256
        index = self.two_graph_index()
2398
2257
        self.assertEqual(('tail', 'ghost'), index.get_parents_with_ghosts('parent'))
2519
2378
             ('tip', 'no-eol,line-delta', (None, 0, 100), ['parent'])])
2520
2379
        self.assertEqual([], self.caught_entries)
2521
2380
 
2522
 
    def test_iter_parents(self):
2523
 
        index1 = self.make_g_index('1', 1, [
2524
 
        # no parents
2525
 
            (('r0', ), 'N0 100', ([], )),
2526
 
        # 1 parent
2527
 
            (('r1', ), '', ([('r0', )], ))])
2528
 
        index2 = self.make_g_index('2', 1, [
2529
 
        # 2 parents
2530
 
            (('r2', ), 'N0 100', ([('r1', ), ('r0', )], )),
2531
 
            ])
2532
 
        combined_index = CombinedGraphIndex([index1, index2])
2533
 
        index = KnitGraphIndex(combined_index)
2534
 
        # XXX TODO a ghost
2535
 
        # cases: each sample data individually:
2536
 
        self.assertEqual(set([('r0', ())]),
2537
 
            set(index.iter_parents(['r0'])))
2538
 
        self.assertEqual(set([('r1', ('r0', ))]),
2539
 
            set(index.iter_parents(['r1'])))
2540
 
        self.assertEqual(set([('r2', ('r1', 'r0'))]),
2541
 
            set(index.iter_parents(['r2'])))
2542
 
        # no nodes returned for a missing node
2543
 
        self.assertEqual(set(),
2544
 
            set(index.iter_parents(['missing'])))
2545
 
        # 1 node returned with missing nodes skipped
2546
 
        self.assertEqual(set([('r1', ('r0', ))]),
2547
 
            set(index.iter_parents(['ghost1', 'r1', 'ghost'])))
2548
 
        # 2 nodes returned
2549
 
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
2550
 
            set(index.iter_parents(['r0', 'r1'])))
2551
 
        # 2 nodes returned, missing skipped
2552
 
        self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
2553
 
            set(index.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))
2554
 
 
2555
 
 
2556
2381
class TestNoParentsGraphIndexKnit(KnitTests):
2557
2382
    """Tests for knits using KnitGraphIndex with no parents."""
2558
2383
 
2593
2418
        return KnitGraphIndex(combined_index, parents=False,
2594
2419
            add_callback=add_callback)
2595
2420
 
2596
 
    def test_get_graph(self):
2597
 
        index = self.two_graph_index()
2598
 
        self.assertEqual(set([
2599
 
            ('tip', ()),
2600
 
            ('tail', ()),
2601
 
            ('parent', ()),
2602
 
            ('separate', ()),
2603
 
            ]), set(index.get_graph()))
2604
 
 
2605
2421
    def test_get_ancestry(self):
2606
2422
        # with no parents, ancestry is always just the key.
2607
2423
        index = self.two_graph_index()
2660
2476
        self.assertEqual(['fulltext', 'no-eol'], index.get_options('tip'))
2661
2477
        self.assertEqual(['fulltext'], index.get_options('parent'))
2662
2478
 
2663
 
    def test_get_parents(self):
2664
 
        index = self.two_graph_index()
2665
 
        self.assertEqual((), index.get_parents('parent'))
2666
 
        # and errors on ghosts.
2667
 
        self.assertRaises(errors.RevisionNotPresent,
2668
 
            index.get_parents, 'ghost')
2669
 
 
2670
2479
    def test_get_parents_with_ghosts(self):
2671
2480
        index = self.two_graph_index()
2672
2481
        self.assertEqual((), index.get_parents_with_ghosts('parent'))
2786
2595
             ('tip', 'no-eol,line-delta', (None, 0, 100), [])])
2787
2596
        self.assertEqual([], self.caught_entries)
2788
2597
 
2789
 
    def test_iter_parents(self):
2790
 
        index = self.two_graph_index()
2791
 
        self.assertEqual(set([
2792
 
            ('tip', ()), ('tail', ()), ('parent', ()), ('separate', ())
2793
 
            ]),
2794
 
            set(index.iter_parents(['tip', 'tail', 'ghost', 'parent', 'separate'])))
2795
 
        self.assertEqual(set([('tip', ())]),
2796
 
            set(index.iter_parents(['tip'])))
2797
 
        self.assertEqual(set(),
2798
 
            set(index.iter_parents([])))
2799
 
 
2800
 
 
2801
2598
class TestPackKnits(KnitTests):
2802
2599
    """Tests that use a _PackAccess and KnitGraphIndex."""
2803
2600
 
2852
2649
            set(result),
2853
2650
            set(index.get_ancestry(ancestry_versions, False)))
2854
2651
 
2855
 
    def assertIterParents(self, knit, versions, parent_versions, result):
2856
 
        """Check the result of an iter_parents call on knit."""
2857
 
        index = self.get_index(knit, knit.get_data_stream(versions))
2858
 
        self.assertEqual(result, index.iter_parents(parent_versions))
2859
 
 
2860
2652
    def assertGetMethod(self, knit, versions, version, result):
2861
2653
        index = self.get_index(knit, knit.get_data_stream(versions))
2862
2654
        self.assertEqual(result, index.get_method(version))
2903
2695
        """Constructing a StreamIndex generates index data."""
2904
2696
        data_list = [('text-a', ['fulltext'], 127, []),
2905
2697
            ('text-b', ['option'], 128, ['text-c'])]
2906
 
        index = _StreamIndex(data_list)
 
2698
        index = _StreamIndex(data_list, None)
2907
2699
        self.assertEqual({'text-a':(['fulltext'], (0, 127), []),
2908
2700
            'text-b':(['option'], (127, 127 + 128), ['text-c'])},
2909
2701
            index._by_version)
2927
2719
        # we thunk across.
2928
2720
        self.assertGetMethod(knit, ['c'], 'b', 'fulltext')
2929
2721
 
2930
 
    def test_iter_parents(self):
2931
 
        knit = self.make_knit_with_4_versions_2_dags()
2932
 
        self.assertIterParents(knit, ['a'], ['a'], [('a', [])])
2933
 
        self.assertIterParents(knit, ['a', 'b'], ['a', 'b'],
2934
 
            [('a', []), ('b', [])])
2935
 
        self.assertIterParents(knit, ['a', 'b', 'c'], ['a', 'b', 'c'],
2936
 
            [('a', []), ('b', []), ('c', ['b', 'a'])])
2937
 
        self.assertIterParents(knit, ['a', 'b', 'c', 'd'],
2938
 
            ['a', 'b', 'c', 'd'],
2939
 
            [('a', []), ('b', []), ('c', ['b', 'a']), ('d', ['e', 'f'])])
2940
 
        self.assertIterParents(knit, ['c'], ['a', 'b', 'c'],
2941
 
            [('c', ['b', 'a'])])
2942
 
 
2943
2722
    def test_get_options(self):
2944
2723
        knit = self.make_knit_with_4_versions_2_dags()
2945
2724
        self.assertGetOptions(knit, 'a', ['no-eol', 'fulltext'])
2947
2726
 
2948
2727
    def test_get_parents_with_ghosts(self):
2949
2728
        knit = self.make_knit_with_4_versions_2_dags()
2950
 
        self.assertGetParentsWithGhosts(knit, ['a'], 'a', [])
2951
 
        self.assertGetParentsWithGhosts(knit, ['c'], 'c', ['b', 'a'])
2952
 
        self.assertGetParentsWithGhosts(knit, ['d'], 'd', ['e', 'f'])
 
2729
        self.assertGetParentsWithGhosts(knit, ['a'], 'a', ())
 
2730
        self.assertGetParentsWithGhosts(knit, ['c'], 'c', ('b', 'a'))
 
2731
        self.assertGetParentsWithGhosts(knit, ['d'], 'd', ('e', 'f'))
2953
2732
 
2954
2733
    def test_get_position(self):
2955
2734
        knit = self.make_knit_with_4_versions_2_dags()
3031
2810
            knit.get_data_stream([]))
3032
2811
        self.assertRaises(errors.KnitCorrupt,
3033
2812
            list, access.get_raw_records([(True, "A", None, None)]))
 
2813
 
 
2814
 
 
2815
class TestFormatSignatures(KnitTests):
 
2816
 
 
2817
    def test_knit_format_signatures(self):
 
2818
        """Different formats of knit have different signature strings."""
 
2819
        knit = self.make_test_knit(name='a', annotate=True)
 
2820
        self.assertEqual('knit-annotated', knit.get_format_signature())
 
2821
        knit = self.make_test_knit(name='p', annotate=False)
 
2822
        self.assertEqual('knit-plain', knit.get_format_signature())