240
246
new_vf = self.get_file('bar')
241
247
for version in multiparent.topo_iter(vf):
242
248
mpdiff = vf.make_mpdiffs([version])[0]
243
new_vf.add_mpdiffs([(version, vf.get_parents(version),
244
vf.get_sha1(version), mpdiff)])
249
new_vf.add_mpdiffs([(version, vf.get_parent_map([version])[version],
250
vf.get_sha1s([version])[0], mpdiff)])
245
251
self.assertEqualDiff(vf.get_text(version),
246
252
new_vf.get_text(version))
347
353
set(f.get_ancestry('rM', topo_sorted=False)))
349
355
def test_mutate_after_finish(self):
356
self._transaction = 'before'
350
357
f = self.get_file()
351
f.transaction_finished()
358
self._transaction = 'after'
352
359
self.assertRaises(errors.OutSideTransaction, f.add_lines, '', [], [])
353
360
self.assertRaises(errors.OutSideTransaction, f.add_lines_with_ghosts, '', [], [])
354
361
self.assertRaises(errors.OutSideTransaction, f.join, '')
355
self.assertRaises(errors.OutSideTransaction, f.clone_text, 'base', 'bar', ['foo'])
357
def test_clear_cache(self):
359
# on a new file it should not error
361
# and after adding content, doing a clear_cache and a get should work.
362
f.add_lines('0', [], ['a'])
364
self.assertEqual(['a'], f.get_lines('0'))
366
363
def test_clone_text(self):
367
364
f = self.get_file()
368
365
f.add_lines('r0', [], ['a\n', 'b\n'])
369
f.clone_text('r1', 'r0', ['r0'])
366
self.applyDeprecated(one_four, f.clone_text, 'r1', 'r0', ['r0'])
370
367
def verify_file(f):
371
368
self.assertEquals(f.get_lines('r1'), f.get_lines('r0'))
372
369
self.assertEquals(f.get_lines('r1'), ['a\n', 'b\n'])
373
self.assertEquals(f.get_parents('r1'), ['r0'])
370
self.assertEqual({'r1':('r0',)}, f.get_parent_map(['r1']))
375
371
self.assertRaises(RevisionNotPresent,
376
f.clone_text, 'r2', 'rX', [])
372
self.applyDeprecated, one_four, f.clone_text, 'r2', 'rX', [])
377
373
self.assertRaises(RevisionAlreadyPresent,
378
f.clone_text, 'r1', 'r0', [])
374
self.applyDeprecated, one_four, f.clone_text, 'r1', 'r0', [])
380
376
verify_file(self.reopen_file())
382
def test_create_empty(self):
384
f.add_lines('0', [], ['a\n'])
385
new_f = f.create_empty('t', MemoryTransport())
386
# smoke test, specific types should check it is honoured correctly for
387
# non type attributes
388
self.assertEqual([], new_f.versions())
389
self.assertTrue(isinstance(new_f, f.__class__))
391
378
def test_copy_to(self):
392
379
f = self.get_file()
393
380
f.add_lines('0', [], ['a\n'])
394
381
t = MemoryTransport()
395
382
f.copy_to('foo', t)
396
for suffix in f.__class__.get_suffixes():
383
for suffix in self.get_factory().get_suffixes():
397
384
self.assertTrue(t.has('foo' + suffix))
399
386
def test_get_suffixes(self):
400
387
f = self.get_file()
402
self.assertEqual(f.__class__.get_suffixes(), f.__class__.get_suffixes())
403
388
# and should be a list
404
self.assertTrue(isinstance(f.__class__.get_suffixes(), list))
389
self.assertTrue(isinstance(self.get_factory().get_suffixes(), list))
406
391
def build_graph(self, file, graph):
407
392
for node in topo_sort(graph.items()):
441
426
simple_b_gam.update(simple_gam)
442
427
simple_b_gam.update(simple_b)
443
428
self.build_graph(f, complex_graph)
444
self.assertEqual(simple_a, f.get_graph(['a']))
445
self.assertEqual(simple_b, f.get_graph(['b']))
446
self.assertEqual(simple_gam, f.get_graph(['gam']))
447
self.assertEqual(simple_b_gam, f.get_graph(['b', 'gam']))
429
self.assertEqual(simple_a, self.applyDeprecated(one_four, f.get_graph,
431
self.assertEqual(simple_b, self.applyDeprecated(one_four, f.get_graph,
433
self.assertEqual(simple_gam, self.applyDeprecated(one_four,
434
f.get_graph, ['gam']))
435
self.assertEqual(simple_b_gam, self.applyDeprecated(one_four,
436
f.get_graph, ['b', 'gam']))
449
438
def test_get_parents(self):
450
439
f = self.get_file()
453
442
f.add_lines('r2', [], ['a\n', 'b\n'])
454
443
f.add_lines('r3', [], ['a\n', 'b\n'])
455
444
f.add_lines('m', ['r0', 'r1', 'r2', 'r3'], ['a\n', 'b\n'])
456
self.assertEquals(f.get_parents('m'), ['r0', 'r1', 'r2', 'r3'])
445
self.assertEqual(['r0', 'r1', 'r2', 'r3'],
446
self.applyDeprecated(one_four, f.get_parents, 'm'))
458
447
self.assertRaises(RevisionNotPresent,
448
self.applyDeprecated, one_four, f.get_parents, 'y')
450
def test_get_parent_map(self):
452
f.add_lines('r0', [], ['a\n', 'b\n'])
454
{'r0':()}, f.get_parent_map(['r0']))
455
f.add_lines('r1', ['r0'], ['a\n', 'b\n'])
457
{'r1':('r0',)}, f.get_parent_map(['r1']))
461
f.get_parent_map(['r0', 'r1']))
462
f.add_lines('r2', [], ['a\n', 'b\n'])
463
f.add_lines('r3', [], ['a\n', 'b\n'])
464
f.add_lines('m', ['r0', 'r1', 'r2', 'r3'], ['a\n', 'b\n'])
466
{'m':('r0', 'r1', 'r2', 'r3')}, f.get_parent_map(['m']))
467
self.assertEqual({}, f.get_parent_map('y'))
471
f.get_parent_map(['r0', 'y', 'r1']))
461
473
def test_annotate(self):
462
474
f = self.get_file()
511
523
# XXX TODO a ghost
512
524
# cases: each sample data individually:
513
525
self.assertEqual(set([('r0', ())]),
514
set(f.iter_parents(['r0'])))
526
set(self.applyDeprecated(one_four, f.iter_parents, ['r0'])))
515
527
self.assertEqual(set([('r1', ('r0', ))]),
516
set(f.iter_parents(['r1'])))
528
set(self.applyDeprecated(one_four, f.iter_parents, ['r1'])))
517
529
self.assertEqual(set([('r2', ('r1', 'r0'))]),
518
set(f.iter_parents(['r2'])))
530
set(self.applyDeprecated(one_four, f.iter_parents, ['r2'])))
519
531
# no nodes returned for a missing node
520
532
self.assertEqual(set(),
521
set(f.iter_parents(['missing'])))
533
set(self.applyDeprecated(one_four, f.iter_parents, ['missing'])))
522
534
# 1 node returned with missing nodes skipped
523
535
self.assertEqual(set([('r1', ('r0', ))]),
524
set(f.iter_parents(['ghost1', 'r1', 'ghost'])))
536
set(self.applyDeprecated(one_four, f.iter_parents, ['ghost1', 'r1',
525
538
# 2 nodes returned
526
539
self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
527
set(f.iter_parents(['r0', 'r1'])))
540
set(self.applyDeprecated(one_four, f.iter_parents, ['r0', 'r1'])))
528
541
# 2 nodes returned, missing skipped
529
542
self.assertEqual(set([('r0', ()), ('r1', ('r0', ))]),
530
set(f.iter_parents(['a', 'r0', 'b', 'r1', 'c'])))
543
set(self.applyDeprecated(one_four, f.iter_parents,
544
['a', 'r0', 'b', 'r1', 'c'])))
532
546
def test_iter_lines_added_or_present_in_versions(self):
533
547
# test that we get at least an equalset of the lines added by
607
621
vf.add_lines_with_ghosts('notbxbfse', [parent_id_utf8], [])
608
622
except NotImplementedError:
609
623
# check the other ghost apis are also not implemented
610
self.assertRaises(NotImplementedError, vf.has_ghost, 'foo')
611
624
self.assertRaises(NotImplementedError, vf.get_ancestry_with_ghosts, ['foo'])
612
625
self.assertRaises(NotImplementedError, vf.get_parents_with_ghosts, 'foo')
613
self.assertRaises(NotImplementedError, vf.get_graph_with_ghosts)
615
627
vf = self.reopen_file()
616
628
# test key graph related apis: getncestry, _graph, get_parents
618
630
# - these are ghost unaware and must not be reflect ghosts
619
631
self.assertEqual(['notbxbfse'], vf.get_ancestry('notbxbfse'))
620
self.assertEqual([], vf.get_parents('notbxbfse'))
621
self.assertEqual({'notbxbfse':()}, vf.get_graph())
633
self.applyDeprecated(one_four, vf.get_parents, 'notbxbfse'))
634
self.assertEqual({'notbxbfse':()}, self.applyDeprecated(one_four,
622
636
self.assertFalse(vf.has_version(parent_id_utf8))
623
637
# we have _with_ghost apis to give us ghost information.
624
638
self.assertEqual([parent_id_utf8, 'notbxbfse'], vf.get_ancestry_with_ghosts(['notbxbfse']))
625
639
self.assertEqual([parent_id_utf8], vf.get_parents_with_ghosts('notbxbfse'))
626
self.assertEqual({'notbxbfse':[parent_id_utf8]}, vf.get_graph_with_ghosts())
627
self.assertTrue(vf.has_ghost(parent_id_utf8))
640
self.assertEqual({'notbxbfse':(parent_id_utf8,)},
641
self.applyDeprecated(one_four, vf.get_graph_with_ghosts))
642
self.assertTrue(self.applyDeprecated(one_four, vf.has_ghost,
628
644
# if we add something that is a ghost of another, it should correct the
629
645
# results of the prior apis
630
646
vf.add_lines(parent_id_utf8, [], [])
631
647
self.assertEqual([parent_id_utf8, 'notbxbfse'], vf.get_ancestry(['notbxbfse']))
632
self.assertEqual([parent_id_utf8], vf.get_parents('notbxbfse'))
648
self.assertEqual({'notbxbfse':(parent_id_utf8,)},
649
vf.get_parent_map(['notbxbfse']))
633
650
self.assertEqual({parent_id_utf8:(),
634
651
'notbxbfse':(parent_id_utf8, ),
653
self.applyDeprecated(one_four, vf.get_graph))
637
654
self.assertTrue(vf.has_version(parent_id_utf8))
638
655
# we have _with_ghost apis to give us ghost information.
639
656
self.assertEqual([parent_id_utf8, 'notbxbfse'],
640
657
vf.get_ancestry_with_ghosts(['notbxbfse']))
641
658
self.assertEqual([parent_id_utf8], vf.get_parents_with_ghosts('notbxbfse'))
642
self.assertEqual({parent_id_utf8:[],
643
'notbxbfse':[parent_id_utf8],
659
self.assertEqual({parent_id_utf8:(),
660
'notbxbfse':(parent_id_utf8,),
645
vf.get_graph_with_ghosts())
646
self.assertFalse(vf.has_ghost(parent_id_utf8))
662
self.applyDeprecated(one_four, vf.get_graph_with_ghosts))
663
self.assertFalse(self.applyDeprecated(one_four, vf.has_ghost,
648
666
def test_add_lines_with_ghosts_after_normal_revs(self):
649
667
# some versioned file formats allow lines to be added with parent
688
704
vf.add_lines('b', ['a'], ['a\n'])
689
705
# a file differing only in last newline.
690
706
vf.add_lines('c', [], ['a'])
692
'3f786850e387550fdab836ed7e6dc881de23001b', vf.get_sha1('a'))
694
'3f786850e387550fdab836ed7e6dc881de23001b', vf.get_sha1('b'))
696
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8', vf.get_sha1('c'))
707
# Deprecasted single-version API.
709
'3f786850e387550fdab836ed7e6dc881de23001b',
710
self.applyDeprecated(one_four, vf.get_sha1, 'a'))
712
'3f786850e387550fdab836ed7e6dc881de23001b',
713
self.applyDeprecated(one_four, vf.get_sha1, 'b'))
715
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8',
716
self.applyDeprecated(one_four, vf.get_sha1, 'c'))
698
717
self.assertEqual(['3f786850e387550fdab836ed7e6dc881de23001b',
699
718
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8',
700
719
'3f786850e387550fdab836ed7e6dc881de23001b'],
704
723
class TestWeave(TestCaseWithMemoryTransport, VersionedFileTestMixIn):
706
725
def get_file(self, name='foo'):
707
return WeaveFile(name, get_transport(self.get_url('.')), create=True)
726
return WeaveFile(name, get_transport(self.get_url('.')), create=True,
727
get_scope=self.get_transaction)
709
729
def get_file_corrupted_text(self):
710
w = WeaveFile('foo', get_transport(self.get_url('.')), create=True)
730
w = WeaveFile('foo', get_transport(self.get_url('.')), create=True,
731
get_scope=self.get_transaction)
711
732
w.add_lines('v1', [], ['hello\n'])
712
733
w.add_lines('v2', ['v1'], ['hello\n', 'there\n'])
743
764
def reopen_file(self, name='foo', create=False):
744
return WeaveFile(name, get_transport(self.get_url('.')), create=create)
765
return WeaveFile(name, get_transport(self.get_url('.')), create=create,
766
get_scope=self.get_transaction)
746
768
def test_no_implicit_create(self):
747
769
self.assertRaises(errors.NoSuchFile,
750
get_transport(self.get_url('.')))
772
get_transport(self.get_url('.')),
773
get_scope=self.get_transaction)
752
775
def get_factory(self):
780
803
def test_no_implicit_create(self):
781
self.assertRaises(errors.NoSuchFile,
784
get_transport(self.get_url('.')))
804
self.assertRaises(errors.NoSuchFile, self.get_factory(), 'foo',
805
get_transport(self.get_url('.')))
787
808
class TestPlaintextKnit(TestKnit):
788
809
"""Test a knit with no cached annotations"""
790
def _factory(self, name, transport, file_mode=None, access_mode=None,
791
delta=True, create=False):
792
return KnitVersionedFile(name, transport, file_mode, access_mode,
793
KnitPlainFactory(), delta=delta,
796
811
def get_factory(self):
812
return make_file_knit
800
815
class TestPlanMergeVersionedFile(TestCaseWithMemoryTransport):
803
818
TestCaseWithMemoryTransport.setUp(self)
804
self.vf1 = KnitVersionedFile('root', self.get_transport(), create=True)
805
self.vf2 = KnitVersionedFile('root', self.get_transport(), create=True)
819
self.vf1 = make_file_knit('root', self.get_transport(), create=True)
820
self.vf2 = make_file_knit('root', self.get_transport(), create=True)
806
821
self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
807
822
[self.vf1, self.vf2])
843
858
def test_get_parents(self):
844
859
self.setup_abcde()
845
self.assertEqual(['A'], self.plan_merge_vf.get_parents('B'))
846
self.assertEqual(['C'], self.plan_merge_vf.get_parents('D'))
847
self.assertEqual(['B', 'D'], self.plan_merge_vf.get_parents('E:'))
848
error = self.assertRaises(errors.RevisionNotPresent,
849
self.plan_merge_vf.get_parents, 'F')
850
self.assertContainsRe(str(error), '{F} not present in "root"')
860
self.assertEqual({'B':('A',)}, self.plan_merge_vf.get_parent_map(['B']))
861
self.assertEqual({'D':('C',)}, self.plan_merge_vf.get_parent_map(['D']))
862
self.assertEqual({'E:':('B', 'D')},
863
self.plan_merge_vf.get_parent_map(['E:']))
864
self.assertEqual({}, self.plan_merge_vf.get_parent_map(['F']))
869
}, self.plan_merge_vf.get_parent_map(['B', 'D', 'E:', 'F']))
852
871
def test_get_lines(self):
853
872
self.setup_abcde()
1221
1244
overlappedInsertExpected = ['aaa', '<<<<<<< ', 'xxx', 'yyy', '=======',
1222
1245
'xxx', '>>>>>>> ', 'bbb']
1225
class TestFormatSignatures(TestCaseWithMemoryTransport):
1227
def get_knit_file(self, name, annotated):
1229
factory = KnitAnnotateFactory()
1231
factory = KnitPlainFactory()
1232
return KnitVersionedFile(
1233
name, get_transport(self.get_url('.')), create=True,
1236
def test_knit_format_signatures(self):
1237
"""Different formats of knit have different signature strings."""
1238
knit = self.get_knit_file('a', True)
1239
self.assertEqual('knit-annotated', knit.get_format_signature())
1240
knit = self.get_knit_file('p', False)
1241
self.assertEqual('knit-plain', knit.get_format_signature())