/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 breezy/tests/test_merge.py

  • Committer: Jelmer Vernooij
  • Date: 2018-07-08 14:45:27 UTC
  • mto: This revision was merged to the branch mainline in revision 7036.
  • Revision ID: jelmer@jelmer.uk-20180708144527-codhlvdcdg9y0nji
Fix a bunch of merge tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
from ..errors import UnrelatedBranches, NoCommits
38
38
from ..merge import transform_tree, merge_inner, _PlanMerge
39
39
from ..osutils import basename, pathjoin, file_kind
 
40
from ..sixish import int2byte
40
41
from . import (
41
42
    features,
42
43
    TestCaseWithMemoryTransport,
374
375
    def test_weave_cherrypick(self):
375
376
        this_tree, other_tree = self.prepare_cherrypick()
376
377
        merger = _mod_merge.Merger.from_revision_ids(
377
 
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
 
378
            this_tree, b'rev3b', b'rev2b', other_tree.branch)
378
379
        merger.merge_type = _mod_merge.WeaveMerger
379
380
        merger.do_merge()
380
 
        self.assertFileEqual('c\na\n', 'this/file')
 
381
        self.assertFileEqual(b'c\na\n', 'this/file')
381
382
 
382
383
    def test_weave_cannot_reverse_cherrypick(self):
383
384
        this_tree, other_tree = self.prepare_cherrypick()
384
385
        merger = _mod_merge.Merger.from_revision_ids(
385
 
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
 
386
            this_tree, b'rev2b', b'rev3b', other_tree.branch)
386
387
        merger.merge_type = _mod_merge.WeaveMerger
387
388
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
388
389
 
389
390
    def test_merge3_can_reverse_cherrypick(self):
390
391
        this_tree, other_tree = self.prepare_cherrypick()
391
392
        merger = _mod_merge.Merger.from_revision_ids(
392
 
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
 
393
            this_tree, b'rev2b', b'rev3b', other_tree.branch)
393
394
        merger.merge_type = _mod_merge.Merge3Merger
394
395
        merger.do_merge()
395
396
 
407
408
        self.addCleanup(this_tree.unlock)
408
409
 
409
410
        merger = _mod_merge.Merger.from_revision_ids(
410
 
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
 
411
            this_tree, b'rev3b', b'rev2b', other_tree.branch)
411
412
        merger.merge_type = _mod_merge.Merge3Merger
412
413
        merger.do_merge()
413
 
        self.assertFileEqual('a\n'
414
 
                             '<<<<<<< TREE\n'
415
 
                             '=======\n'
416
 
                             'c\n'
417
 
                             '>>>>>>> MERGE-SOURCE\n',
 
414
        self.assertFileEqual(b'a\n'
 
415
                             b'<<<<<<< TREE\n'
 
416
                             b'=======\n'
 
417
                             b'c\n'
 
418
                             b'>>>>>>> MERGE-SOURCE\n',
418
419
                             'this/file')
419
420
 
420
421
    def test_merge_reverse_revision_range(self):
445
446
        this_tree.lock_write()
446
447
        self.addCleanup(this_tree.unlock)
447
448
        merger = _mod_merge.Merger.from_revision_ids(
448
 
            this_tree, 'rev2b', other_branch=other_tree.branch)
 
449
            this_tree, b'rev2b', other_branch=other_tree.branch)
449
450
        merger.merge_type = _mod_merge.Merge3Merger
450
451
        tree_merger = merger.make_merger()
451
452
        self.assertIs(_mod_merge.Merge3Merger, tree_merger.__class__)
452
 
        self.assertEqual('rev2b',
 
453
        self.assertEqual(b'rev2b',
453
454
            tree_merger.other_tree.get_revision_id())
454
 
        self.assertEqual('rev1',
 
455
        self.assertEqual(b'rev1',
455
456
            tree_merger.base_tree.get_revision_id())
456
457
        self.assertEqual(other_tree.branch, tree_merger.other_branch)
457
458
 
474
475
        tt = tree_merger.make_preview_transform()
475
476
        self.addCleanup(tt.finalize)
476
477
        preview_tree = tt.get_preview_tree()
477
 
        tree_file = this_tree.get_file('file')
478
 
        try:
479
 
            self.assertEqual('1\n2a\n', tree_file.read())
480
 
        finally:
481
 
            tree_file.close()
482
 
        preview_file = preview_tree.get_file('file')
483
 
        try:
484
 
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
485
 
        finally:
486
 
            preview_file.close()
 
478
        with this_tree.get_file('file') as tree_file:
 
479
            self.assertEqual(b'1\n2a\n', tree_file.read())
 
480
        with preview_tree.get_file('file') as preview_file:
 
481
            self.assertEqual(b'2b\n1\n2a\n', preview_file.read())
487
482
 
488
483
    def test_do_merge(self):
489
484
        this_tree = self.make_branch_and_tree('this')
566
561
        self.plan_merge_vf.fallback_versionedfiles.append(self.vf)
567
562
 
568
563
    def add_version(self, key, parents, text):
569
 
        self.vf.add_lines(key, parents, [c+'\n' for c in text])
 
564
        self.vf.add_lines(key, parents, [int2byte(c)+b'\n' for c in bytearray(text)])
570
565
 
571
566
    def add_rev(self, prefix, revision_id, parents, text):
572
567
        self.add_version((prefix, revision_id), [(prefix, p) for p in parents],
577
572
                                     [c+'\n' for c in text])
578
573
 
579
574
    def setup_plan_merge(self):
580
 
        self.add_rev('root', 'A', [], 'abc')
581
 
        self.add_rev('root', 'B', ['A'], 'acehg')
582
 
        self.add_rev('root', 'C', ['A'], 'fabg')
583
 
        return _PlanMerge('B', 'C', self.plan_merge_vf, ('root',))
 
575
        self.add_rev(b'root', b'A', [], b'abc')
 
576
        self.add_rev(b'root', b'B', [b'A'], b'acehg')
 
577
        self.add_rev(b'root', b'C', [b'A'], b'fabg')
 
578
        return _PlanMerge(b'B', b'C', self.plan_merge_vf, (b'root',))
584
579
 
585
580
    def setup_plan_merge_uncommitted(self):
586
 
        self.add_version(('root', 'A'), [], 'abc')
587
 
        self.add_uncommitted_version(('root', 'B:'), [('root', 'A')], 'acehg')
588
 
        self.add_uncommitted_version(('root', 'C:'), [('root', 'A')], 'fabg')
589
 
        return _PlanMerge('B:', 'C:', self.plan_merge_vf, ('root',))
 
581
        self.add_version((b'root', b'A'), [], b'abc')
 
582
        self.add_uncommitted_version((b'root', b'B:'), [(b'root', b'A')], b'acehg')
 
583
        self.add_uncommitted_version((b'root', b'C:'), [(b'root', b'A')], b'fabg')
 
584
        return _PlanMerge(b'B:', b'C:', self.plan_merge_vf, (b'root',))
590
585
 
591
586
    def test_base_from_plan(self):
592
587
        self.setup_plan_merge()
593
 
        plan = self.plan_merge_vf.plan_merge('B', 'C')
 
588
        plan = self.plan_merge_vf.plan_merge(b'B', b'C')
594
589
        pwm = versionedfile.PlanWeaveMerge(plan)
595
 
        self.assertEqual(['a\n', 'b\n', 'c\n'], pwm.base_from_plan())
 
590
        self.assertEqual([b'a\n', b'b\n', b'c\n'], pwm.base_from_plan())
596
591
 
597
592
    def test_unique_lines(self):
598
593
        plan = self.setup_plan_merge()
599
594
        self.assertEqual(plan._unique_lines(
600
 
            plan._get_matching_blocks('B', 'C')),
 
595
            plan._get_matching_blocks(b'B', b'C')),
601
596
            ([1, 2, 3], [0, 2]))
602
597
 
603
598
    def test_plan_merge(self):
604
599
        self.setup_plan_merge()
605
 
        plan = self.plan_merge_vf.plan_merge('B', 'C')
 
600
        plan = self.plan_merge_vf.plan_merge(b'B', b'C')
606
601
        self.assertEqual([
607
 
                          ('new-b', 'f\n'),
608
 
                          ('unchanged', 'a\n'),
609
 
                          ('killed-a', 'b\n'),
610
 
                          ('killed-b', 'c\n'),
611
 
                          ('new-a', 'e\n'),
612
 
                          ('new-a', 'h\n'),
613
 
                          ('new-a', 'g\n'),
614
 
                          ('new-b', 'g\n')],
 
602
                          ('new-b', b'f\n'),
 
603
                          ('unchanged', b'a\n'),
 
604
                          ('killed-a', b'b\n'),
 
605
                          ('killed-b', b'c\n'),
 
606
                          ('new-a', b'e\n'),
 
607
                          ('new-a', b'h\n'),
 
608
                          ('new-a', b'g\n'),
 
609
                          ('new-b', b'g\n')],
615
610
                         list(plan))
616
611
 
617
612
    def test_plan_merge_cherrypick(self):
618
 
        self.add_rev('root', 'A', [], 'abc')
619
 
        self.add_rev('root', 'B', ['A'], 'abcde')
620
 
        self.add_rev('root', 'C', ['A'], 'abcefg')
621
 
        self.add_rev('root', 'D', ['A', 'B', 'C'], 'abcdegh')
622
 
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf, ('root',))
 
613
        self.add_rev(b'root', b'A', [], b'abc')
 
614
        self.add_rev(b'root', b'B', [b'A'], b'abcde')
 
615
        self.add_rev(b'root', b'C', [b'A'], b'abcefg')
 
616
        self.add_rev(b'root', b'D', [b'A', b'B', b'C'], b'abcdegh')
 
617
        my_plan = _PlanMerge(b'B', b'D', self.plan_merge_vf, (b'root',))
623
618
        # We shortcut when one text supersedes the other in the per-file graph.
624
619
        # We don't actually need to compare the texts at this point.
625
620
        self.assertEqual([
626
 
                          ('new-b', 'a\n'),
627
 
                          ('new-b', 'b\n'),
628
 
                          ('new-b', 'c\n'),
629
 
                          ('new-b', 'd\n'),
630
 
                          ('new-b', 'e\n'),
631
 
                          ('new-b', 'g\n'),
632
 
                          ('new-b', 'h\n')],
 
621
                          ('new-b', b'a\n'),
 
622
                          ('new-b', b'b\n'),
 
623
                          ('new-b', b'c\n'),
 
624
                          ('new-b', b'd\n'),
 
625
                          ('new-b', b'e\n'),
 
626
                          ('new-b', b'g\n'),
 
627
                          ('new-b', b'h\n')],
633
628
                          list(my_plan.plan_merge()))
634
629
 
635
630
    def test_plan_merge_no_common_ancestor(self):
636
 
        self.add_rev('root', 'A', [], 'abc')
637
 
        self.add_rev('root', 'B', [], 'xyz')
638
 
        my_plan = _PlanMerge('A', 'B', self.plan_merge_vf, ('root',))
 
631
        self.add_rev(b'root', b'A', [], b'abc')
 
632
        self.add_rev(b'root', b'B', [], b'xyz')
 
633
        my_plan = _PlanMerge(b'A', b'B', self.plan_merge_vf, (b'root',))
639
634
        self.assertEqual([
640
 
                          ('new-a', 'a\n'),
641
 
                          ('new-a', 'b\n'),
642
 
                          ('new-a', 'c\n'),
643
 
                          ('new-b', 'x\n'),
644
 
                          ('new-b', 'y\n'),
645
 
                          ('new-b', 'z\n')],
 
635
                          ('new-a', b'a\n'),
 
636
                          ('new-a', b'b\n'),
 
637
                          ('new-a', b'c\n'),
 
638
                          ('new-b', b'x\n'),
 
639
                          ('new-b', b'y\n'),
 
640
                          ('new-b', b'z\n')],
646
641
                          list(my_plan.plan_merge()))
647
642
 
648
643
    def test_plan_merge_tail_ancestors(self):
665
660
        # are already present in E
666
661
 
667
662
        # Introduce the base text
668
 
        self.add_rev('root', 'A', [], 'abc')
 
663
        self.add_rev(b'root', b'A', [], b'abc')
669
664
        # Introduces a new line B
670
 
        self.add_rev('root', 'B', ['A'], 'aBbc')
 
665
        self.add_rev(b'root', b'B', [b'A'], b'aBbc')
671
666
        # Introduces a new line C
672
 
        self.add_rev('root', 'C', ['A'], 'abCc')
 
667
        self.add_rev(b'root', b'C', [b'A'], b'abCc')
673
668
        # Introduce new line D
674
 
        self.add_rev('root', 'D', ['B'], 'DaBbc')
 
669
        self.add_rev(b'root', b'D', [b'B'], b'DaBbc')
675
670
        # Merges B and C by just incorporating both
676
 
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
 
671
        self.add_rev(b'root', b'E', [b'B', b'C'], b'aBbCc')
677
672
        # Introduce new line F
678
 
        self.add_rev('root', 'F', ['C'], 'abCcF')
 
673
        self.add_rev(b'root', b'F', [b'C'], b'abCcF')
679
674
        # Merge D & E by just combining the texts
680
 
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
 
675
        self.add_rev(b'root', b'G', [b'D', b'E'], b'DaBbCc')
681
676
        # Merge F & E by just combining the texts
682
 
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
 
677
        self.add_rev(b'root', b'H', [b'F', b'E'], b'aBbCcF')
683
678
        # Merge G & H by just combining texts
684
 
        self.add_rev('root', 'I', ['G', 'H'], 'DaBbCcF')
 
679
        self.add_rev(b'root', b'I', [b'G', b'H'], b'DaBbCcF')
685
680
        # Merge G & H but supersede an old line in B
686
 
        self.add_rev('root', 'J', ['H', 'G'], 'DaJbCcF')
687
 
        plan = self.plan_merge_vf.plan_merge('I', 'J')
 
681
        self.add_rev(b'root', b'J', [b'H', b'G'], b'DaJbCcF')
 
682
        plan = self.plan_merge_vf.plan_merge(b'I', b'J')
688
683
        self.assertEqual([
689
 
                          ('unchanged', 'D\n'),
690
 
                          ('unchanged', 'a\n'),
691
 
                          ('killed-b', 'B\n'),
692
 
                          ('new-b', 'J\n'),
693
 
                          ('unchanged', 'b\n'),
694
 
                          ('unchanged', 'C\n'),
695
 
                          ('unchanged', 'c\n'),
696
 
                          ('unchanged', 'F\n')],
 
684
                          ('unchanged', b'D\n'),
 
685
                          ('unchanged', b'a\n'),
 
686
                          ('killed-b', b'B\n'),
 
687
                          ('new-b', b'J\n'),
 
688
                          ('unchanged', b'b\n'),
 
689
                          ('unchanged', b'C\n'),
 
690
                          ('unchanged', b'c\n'),
 
691
                          ('unchanged', b'F\n')],
697
692
                         list(plan))
698
693
 
699
694
    def test_plan_merge_tail_triple_ancestors(self):
714
709
        # a third LCA that doesn't add new lines, but will trigger our more
715
710
        # involved ancestry logic
716
711
 
717
 
        self.add_rev('root', 'A', [], 'abc')
718
 
        self.add_rev('root', 'B', ['A'], 'aBbc')
719
 
        self.add_rev('root', 'C', ['A'], 'abCc')
720
 
        self.add_rev('root', 'D', ['B'], 'DaBbc')
721
 
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
722
 
        self.add_rev('root', 'F', ['C'], 'abCcF')
723
 
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
724
 
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
725
 
        self.add_rev('root', 'Q', ['E'], 'aBbCc')
726
 
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DaBbCcF')
 
712
        self.add_rev(b'root', b'A', [], b'abc')
 
713
        self.add_rev(b'root', b'B', [b'A'], b'aBbc')
 
714
        self.add_rev(b'root', b'C', [b'A'], b'abCc')
 
715
        self.add_rev(b'root', b'D', [b'B'], b'DaBbc')
 
716
        self.add_rev(b'root', b'E', [b'B', b'C'], b'aBbCc')
 
717
        self.add_rev(b'root', b'F', [b'C'], 'abCcF')
 
718
        self.add_rev(b'root', b'G', [b'D', b'E'], b'DaBbCc')
 
719
        self.add_rev(b'root', b'H', [b'F', b'E'], b'aBbCcF')
 
720
        self.add_rev(b'root', b'Q', [b'E'], 'aBbCc')
 
721
        self.add_rev(b'root', b'I', [b'G', b'Q', b'H'], b'DaBbCcF')
727
722
        # Merge G & H but supersede an old line in B
728
 
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DaJbCcF')
729
 
        plan = self.plan_merge_vf.plan_merge('I', 'J')
 
723
        self.add_rev(b'root', b'J', [b'H', b'Q', b'G'], b'DaJbCcF')
 
724
        plan = self.plan_merge_vf.plan_merge(b'I', b'J')
730
725
        self.assertEqual([
731
 
                          ('unchanged', 'D\n'),
732
 
                          ('unchanged', 'a\n'),
733
 
                          ('killed-b', 'B\n'),
734
 
                          ('new-b', 'J\n'),
735
 
                          ('unchanged', 'b\n'),
736
 
                          ('unchanged', 'C\n'),
737
 
                          ('unchanged', 'c\n'),
738
 
                          ('unchanged', 'F\n')],
 
726
                          ('unchanged', b'D\n'),
 
727
                          ('unchanged', b'a\n'),
 
728
                          ('killed-b', b'B\n'),
 
729
                          ('new-b', b'J\n'),
 
730
                          ('unchanged', b'b\n'),
 
731
                          ('unchanged', b'C\n'),
 
732
                          ('unchanged', b'c\n'),
 
733
                          ('unchanged', b'F\n')],
739
734
                         list(plan))
740
735
 
741
736
    def test_plan_merge_2_tail_triple_ancestors(self):
754
749
        # This is meant to test after hitting a 3-way LCA, and multiple tail
755
750
        # ancestors (only have NULL_REVISION in common)
756
751
 
757
 
        self.add_rev('root', 'A', [], 'abc')
758
 
        self.add_rev('root', 'B', [], 'def')
759
 
        self.add_rev('root', 'D', ['A'], 'Dabc')
760
 
        self.add_rev('root', 'E', ['A', 'B'], 'abcdef')
761
 
        self.add_rev('root', 'F', ['B'], 'defF')
762
 
        self.add_rev('root', 'G', ['D', 'E'], 'Dabcdef')
763
 
        self.add_rev('root', 'H', ['F', 'E'], 'abcdefF')
764
 
        self.add_rev('root', 'Q', ['E'], 'abcdef')
765
 
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DabcdefF')
 
752
        self.add_rev(b'root', b'A', [], b'abc')
 
753
        self.add_rev(b'root', b'B', [], b'def')
 
754
        self.add_rev(b'root', b'D', [b'A'], b'Dabc')
 
755
        self.add_rev(b'root', b'E', [b'A', b'B'], b'abcdef')
 
756
        self.add_rev(b'root', b'F', [b'B'], b'defF')
 
757
        self.add_rev(b'root', b'G', [b'D', b'E'], b'Dabcdef')
 
758
        self.add_rev(b'root', b'H', [b'F', b'E'], b'abcdefF')
 
759
        self.add_rev(b'root', b'Q', [b'E'], b'abcdef')
 
760
        self.add_rev(b'root', b'I', [b'G', b'Q', b'H'], b'DabcdefF')
766
761
        # Merge G & H but supersede an old line in B
767
 
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DabcdJfF')
768
 
        plan = self.plan_merge_vf.plan_merge('I', 'J')
 
762
        self.add_rev(b'root', b'J', [b'H', b'Q', b'G'], b'DabcdJfF')
 
763
        plan = self.plan_merge_vf.plan_merge(b'I', b'J')
769
764
        self.assertEqual([
770
 
                          ('unchanged', 'D\n'),
771
 
                          ('unchanged', 'a\n'),
772
 
                          ('unchanged', 'b\n'),
773
 
                          ('unchanged', 'c\n'),
774
 
                          ('unchanged', 'd\n'),
775
 
                          ('killed-b', 'e\n'),
776
 
                          ('new-b', 'J\n'),
777
 
                          ('unchanged', 'f\n'),
778
 
                          ('unchanged', 'F\n')],
 
765
                          ('unchanged', b'D\n'),
 
766
                          ('unchanged', b'a\n'),
 
767
                          ('unchanged', b'b\n'),
 
768
                          ('unchanged', b'c\n'),
 
769
                          ('unchanged', b'd\n'),
 
770
                          ('killed-b', b'e\n'),
 
771
                          ('new-b', b'J\n'),
 
772
                          ('unchanged', b'f\n'),
 
773
                          ('unchanged', b'F\n')],
779
774
                         list(plan))
780
775
 
781
776
    def test_plan_merge_uncommitted_files(self):
782
777
        self.setup_plan_merge_uncommitted()
783
 
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
 
778
        plan = self.plan_merge_vf.plan_merge(b'B:', b'C:')
784
779
        self.assertEqual([
785
 
                          ('new-b', 'f\n'),
786
 
                          ('unchanged', 'a\n'),
787
 
                          ('killed-a', 'b\n'),
788
 
                          ('killed-b', 'c\n'),
789
 
                          ('new-a', 'e\n'),
790
 
                          ('new-a', 'h\n'),
791
 
                          ('new-a', 'g\n'),
792
 
                          ('new-b', 'g\n')],
 
780
                          ('new-b', b'f\n'),
 
781
                          ('unchanged', b'a\n'),
 
782
                          ('killed-a', b'b\n'),
 
783
                          ('killed-b', b'c\n'),
 
784
                          ('new-a', b'e\n'),
 
785
                          ('new-a', b'h\n'),
 
786
                          ('new-a', b'g\n'),
 
787
                          ('new-b', b'g\n')],
793
788
                         list(plan))
794
789
 
795
790
    def test_plan_merge_insert_order(self):
800
795
        same ordering, then the lines match the parents, if they don't only
801
796
        *some* of the lines match.
802
797
        """
803
 
        self.add_rev('root', 'A', [], 'abcdef')
804
 
        self.add_rev('root', 'B', ['A'], 'abwxcdef')
805
 
        self.add_rev('root', 'C', ['A'], 'abyzcdef')
 
798
        self.add_rev(b'root', b'A', [], b'abcdef')
 
799
        self.add_rev(b'root', b'B', [b'A'], b'abwxcdef')
 
800
        self.add_rev(b'root', b'C', [b'A'], b'abyzcdef')
806
801
        # Merge, and resolve the conflict by adding *both* sets of lines
807
802
        # If we get the ordering wrong, these will look like new lines in D,
808
803
        # rather than carried over from B, C
809
 
        self.add_rev('root', 'D', ['B', 'C'],
810
 
                         'abwxyzcdef')
 
804
        self.add_rev(b'root', b'D', [b'B', b'C'],
 
805
                         b'abwxyzcdef')
811
806
        # Supersede the lines in B and delete the lines in C, which will
812
807
        # conflict if they are treated as being in D
813
 
        self.add_rev('root', 'E', ['C', 'B'],
814
 
                         'abnocdef')
 
808
        self.add_rev(b'root', b'E', [b'C', b'B'],
 
809
                         b'abnocdef')
815
810
        # Same thing for the lines in C
816
 
        self.add_rev('root', 'F', ['C'], 'abpqcdef')
817
 
        plan = self.plan_merge_vf.plan_merge('D', 'E')
 
811
        self.add_rev(b'root', b'F', [b'C'], b'abpqcdef')
 
812
        plan = self.plan_merge_vf.plan_merge(b'D', b'E')
818
813
        self.assertEqual([
819
 
                          ('unchanged', 'a\n'),
820
 
                          ('unchanged', 'b\n'),
821
 
                          ('killed-b', 'w\n'),
822
 
                          ('killed-b', 'x\n'),
823
 
                          ('killed-b', 'y\n'),
824
 
                          ('killed-b', 'z\n'),
825
 
                          ('new-b', 'n\n'),
826
 
                          ('new-b', 'o\n'),
827
 
                          ('unchanged', 'c\n'),
828
 
                          ('unchanged', 'd\n'),
829
 
                          ('unchanged', 'e\n'),
830
 
                          ('unchanged', 'f\n')],
 
814
                          ('unchanged', b'a\n'),
 
815
                          ('unchanged', b'b\n'),
 
816
                          ('killed-b', b'w\n'),
 
817
                          ('killed-b', b'x\n'),
 
818
                          ('killed-b', b'y\n'),
 
819
                          ('killed-b', b'z\n'),
 
820
                          ('new-b', b'n\n'),
 
821
                          ('new-b', b'o\n'),
 
822
                          ('unchanged', b'c\n'),
 
823
                          ('unchanged', b'd\n'),
 
824
                          ('unchanged', b'e\n'),
 
825
                          ('unchanged', b'f\n')],
831
826
                         list(plan))
832
 
        plan = self.plan_merge_vf.plan_merge('E', 'D')
 
827
        plan = self.plan_merge_vf.plan_merge(b'E', b'D')
833
828
        # Going in the opposite direction shows the effect of the opposite plan
834
829
        self.assertEqual([
835
 
                          ('unchanged', 'a\n'),
836
 
                          ('unchanged', 'b\n'),
837
 
                          ('new-b', 'w\n'),
838
 
                          ('new-b', 'x\n'),
839
 
                          ('killed-a', 'y\n'),
840
 
                          ('killed-a', 'z\n'),
841
 
                          ('killed-both', 'w\n'),
842
 
                          ('killed-both', 'x\n'),
843
 
                          ('new-a', 'n\n'),
844
 
                          ('new-a', 'o\n'),
845
 
                          ('unchanged', 'c\n'),
846
 
                          ('unchanged', 'd\n'),
847
 
                          ('unchanged', 'e\n'),
848
 
                          ('unchanged', 'f\n')],
 
830
                          ('unchanged', b'a\n'),
 
831
                          ('unchanged', b'b\n'),
 
832
                          ('new-b', b'w\n'),
 
833
                          ('new-b', b'x\n'),
 
834
                          ('killed-a', b'y\n'),
 
835
                          ('killed-a', b'z\n'),
 
836
                          ('killed-both', b'w\n'),
 
837
                          ('killed-both', b'x\n'),
 
838
                          ('new-a', b'n\n'),
 
839
                          ('new-a', b'o\n'),
 
840
                          ('unchanged', b'c\n'),
 
841
                          ('unchanged', b'd\n'),
 
842
                          ('unchanged', b'e\n'),
 
843
                          ('unchanged', b'f\n')],
849
844
                         list(plan))
850
845
 
851
846
    def test_plan_merge_criss_cross(self):
873
868
        #   'foo', it should appear as superseding the value in F (since it
874
869
        #   came from B), rather than conflict because of the resolution during
875
870
        #   C & D.
876
 
        self.add_rev('root', 'XX', [], 'qrs')
877
 
        self.add_rev('root', 'A', ['XX'], 'abcdef')
878
 
        self.add_rev('root', 'B', ['A'], 'axcdef')
879
 
        self.add_rev('root', 'C', ['B'], 'axcdefg')
880
 
        self.add_rev('root', 'D', ['B'], 'haxcdef')
881
 
        self.add_rev('root', 'E', ['A'], 'abcdyf')
 
871
        self.add_rev(b'root', b'XX', [], b'qrs')
 
872
        self.add_rev(b'root', b'A', [b'XX'], b'abcdef')
 
873
        self.add_rev(b'root', b'B', [b'A'], b'axcdef')
 
874
        self.add_rev(b'root', b'C', [b'B'], b'axcdefg')
 
875
        self.add_rev(b'root', b'D', [b'B'], b'haxcdef')
 
876
        self.add_rev(b'root', b'E', [b'A'], b'abcdyf')
882
877
        # Simple combining of all texts
883
 
        self.add_rev('root', 'F', ['C', 'D', 'E'], 'haxcdyfg')
 
878
        self.add_rev(b'root', b'F', [b'C', b'D', b'E'], b'haxcdyfg')
884
879
        # combine and supersede 'x'
885
 
        self.add_rev('root', 'G', ['C', 'D', 'E'], 'hazcdyfg')
886
 
        plan = self.plan_merge_vf.plan_merge('F', 'G')
 
880
        self.add_rev(b'root', b'G', [b'C', b'D', b'E'], b'hazcdyfg')
 
881
        plan = self.plan_merge_vf.plan_merge(b'F', b'G')
887
882
        self.assertEqual([
888
 
                          ('unchanged', 'h\n'),
889
 
                          ('unchanged', 'a\n'),
890
 
                          ('killed-base', 'b\n'),
891
 
                          ('killed-b', 'x\n'),
892
 
                          ('new-b', 'z\n'),
893
 
                          ('unchanged', 'c\n'),
894
 
                          ('unchanged', 'd\n'),
895
 
                          ('killed-base', 'e\n'),
896
 
                          ('unchanged', 'y\n'),
897
 
                          ('unchanged', 'f\n'),
898
 
                          ('unchanged', 'g\n')],
 
883
                          ('unchanged', b'h\n'),
 
884
                          ('unchanged', b'a\n'),
 
885
                          ('killed-base', b'b\n'),
 
886
                          ('killed-b', b'x\n'),
 
887
                          ('new-b', b'z\n'),
 
888
                          ('unchanged', b'c\n'),
 
889
                          ('unchanged', b'd\n'),
 
890
                          ('killed-base', b'e\n'),
 
891
                          ('unchanged', b'y\n'),
 
892
                          ('unchanged', b'f\n'),
 
893
                          ('unchanged', b'g\n')],
899
894
                         list(plan))
900
 
        plan = self.plan_merge_vf.plan_lca_merge('F', 'G')
 
895
        plan = self.plan_merge_vf.plan_lca_merge(b'F', b'G')
901
896
        # This is one of the main differences between plan_merge and
902
897
        # plan_lca_merge. plan_lca_merge generates a conflict for 'x => z',
903
898
        # because 'x' was not present in one of the bases. However, in this
904
899
        # case it is spurious because 'x' does not exist in the global base A.
905
900
        self.assertEqual([
906
 
                          ('unchanged', 'h\n'),
907
 
                          ('unchanged', 'a\n'),
908
 
                          ('conflicted-a', 'x\n'),
909
 
                          ('new-b', 'z\n'),
910
 
                          ('unchanged', 'c\n'),
911
 
                          ('unchanged', 'd\n'),
912
 
                          ('unchanged', 'y\n'),
913
 
                          ('unchanged', 'f\n'),
914
 
                          ('unchanged', 'g\n')],
 
901
                          ('unchanged', b'h\n'),
 
902
                          ('unchanged', b'a\n'),
 
903
                          ('conflicted-a', b'x\n'),
 
904
                          ('new-b', b'z\n'),
 
905
                          ('unchanged', b'c\n'),
 
906
                          ('unchanged', b'd\n'),
 
907
                          ('unchanged', b'y\n'),
 
908
                          ('unchanged', b'f\n'),
 
909
                          ('unchanged', b'g\n')],
915
910
                         list(plan))
916
911
 
917
912
    def test_criss_cross_flip_flop(self):
920
915
        #       XX      unused ancestor, should not show up in the weave
921
916
        #       |
922
917
        #       A       Unique LCA
923
 
        #      / \  
 
918
        #      / \
924
919
        #     B   C     B & C both introduce a new line
925
 
        #     |\ /|  
926
 
        #     | X |  
927
 
        #     |/ \| 
 
920
        #     |\ /|
 
921
        #     | X |
 
922
        #     |/ \|
928
923
        #     D   E     B & C are both merged, so both are common ancestors
929
924
        #               In the process of merging, both sides order the new
930
925
        #               lines differently
931
926
        #
932
 
        self.add_rev('root', 'XX', [], 'qrs')
933
 
        self.add_rev('root', 'A', ['XX'], 'abcdef')
934
 
        self.add_rev('root', 'B', ['A'], 'abcdgef')
935
 
        self.add_rev('root', 'C', ['A'], 'abcdhef')
936
 
        self.add_rev('root', 'D', ['B', 'C'], 'abcdghef')
937
 
        self.add_rev('root', 'E', ['C', 'B'], 'abcdhgef')
938
 
        plan = list(self.plan_merge_vf.plan_merge('D', 'E'))
 
927
        self.add_rev(b'root', b'XX', [], b'qrs')
 
928
        self.add_rev(b'root', b'A', [b'XX'], b'abcdef')
 
929
        self.add_rev(b'root', b'B', [b'A'], b'abcdgef')
 
930
        self.add_rev(b'root', b'C', [b'A'], b'abcdhef')
 
931
        self.add_rev(b'root', b'D', [b'B', b'C'], b'abcdghef')
 
932
        self.add_rev(b'root', b'E', [b'C', b'B'], b'abcdhgef')
 
933
        plan = list(self.plan_merge_vf.plan_merge(b'D', b'E'))
939
934
        self.assertEqual([
940
 
                          ('unchanged', 'a\n'),
941
 
                          ('unchanged', 'b\n'),
942
 
                          ('unchanged', 'c\n'),
943
 
                          ('unchanged', 'd\n'),
944
 
                          ('new-b', 'h\n'),
945
 
                          ('unchanged', 'g\n'),
946
 
                          ('killed-b', 'h\n'),
947
 
                          ('unchanged', 'e\n'),
948
 
                          ('unchanged', 'f\n'),
 
935
                          ('unchanged', b'a\n'),
 
936
                          ('unchanged', b'b\n'),
 
937
                          ('unchanged', b'c\n'),
 
938
                          ('unchanged', b'd\n'),
 
939
                          ('new-b', b'h\n'),
 
940
                          ('unchanged', b'g\n'),
 
941
                          ('killed-b', b'h\n'),
 
942
                          ('unchanged', b'e\n'),
 
943
                          ('unchanged', b'f\n'),
949
944
                         ], plan)
950
945
        pwm = versionedfile.PlanWeaveMerge(plan)
951
 
        self.assertEqualDiff('\n'.join('abcdghef') + '\n',
952
 
                             ''.join(pwm.base_from_plan()))
 
946
        self.assertEqualDiff(b'\n'.join(b'abcdghef') + b'\n',
 
947
                             b''.join(pwm.base_from_plan()))
953
948
        # Reversing the order reverses the merge plan, and final order of 'hg'
954
949
        # => 'gh'
955
 
        plan = list(self.plan_merge_vf.plan_merge('E', 'D'))
 
950
        plan = list(self.plan_merge_vf.plan_merge(b'E', b'D'))
956
951
        self.assertEqual([
957
 
                          ('unchanged', 'a\n'),
958
 
                          ('unchanged', 'b\n'),
959
 
                          ('unchanged', 'c\n'),
960
 
                          ('unchanged', 'd\n'),
961
 
                          ('new-b', 'g\n'),
962
 
                          ('unchanged', 'h\n'),
963
 
                          ('killed-b', 'g\n'),
964
 
                          ('unchanged', 'e\n'),
965
 
                          ('unchanged', 'f\n'),
 
952
                          ('unchanged', b'a\n'),
 
953
                          ('unchanged', b'b\n'),
 
954
                          ('unchanged', b'c\n'),
 
955
                          ('unchanged', b'd\n'),
 
956
                          ('new-b', b'g\n'),
 
957
                          ('unchanged', b'h\n'),
 
958
                          ('killed-b', b'g\n'),
 
959
                          ('unchanged', b'e\n'),
 
960
                          ('unchanged', b'f\n'),
966
961
                         ], plan)
967
962
        pwm = versionedfile.PlanWeaveMerge(plan)
968
 
        self.assertEqualDiff('\n'.join('abcdhgef') + '\n',
969
 
                             ''.join(pwm.base_from_plan()))
 
963
        self.assertEqualDiff(b'\n'.join(b'abcdhgef') + b'\n',
 
964
                             b''.join(pwm.base_from_plan()))
970
965
        # This is where lca differs, in that it (fairly correctly) determines
971
966
        # that there is a conflict because both sides resolved the merge
972
967
        # differently
973
 
        plan = list(self.plan_merge_vf.plan_lca_merge('D', 'E'))
 
968
        plan = list(self.plan_merge_vf.plan_lca_merge(b'D', b'E'))
974
969
        self.assertEqual([
975
 
                          ('unchanged', 'a\n'),
976
 
                          ('unchanged', 'b\n'),
977
 
                          ('unchanged', 'c\n'),
978
 
                          ('unchanged', 'd\n'),
979
 
                          ('conflicted-b', 'h\n'),
980
 
                          ('unchanged', 'g\n'),
981
 
                          ('conflicted-a', 'h\n'),
982
 
                          ('unchanged', 'e\n'),
983
 
                          ('unchanged', 'f\n'),
 
970
                          ('unchanged', b'a\n'),
 
971
                          ('unchanged', b'b\n'),
 
972
                          ('unchanged', b'c\n'),
 
973
                          ('unchanged', b'd\n'),
 
974
                          ('conflicted-b', b'h\n'),
 
975
                          ('unchanged', b'g\n'),
 
976
                          ('conflicted-a', b'h\n'),
 
977
                          ('unchanged', b'e\n'),
 
978
                          ('unchanged', b'f\n'),
984
979
                         ], plan)
985
980
        pwm = versionedfile.PlanWeaveMerge(plan)
986
 
        self.assertEqualDiff('\n'.join('abcdgef') + '\n',
987
 
                             ''.join(pwm.base_from_plan()))
 
981
        self.assertEqualDiff(b'\n'.join(b'abcdgef') + b'\n',
 
982
                             b''.join(pwm.base_from_plan()))
988
983
        # Reversing it changes what line is doubled, but still gives a
989
984
        # double-conflict
990
 
        plan = list(self.plan_merge_vf.plan_lca_merge('E', 'D'))
 
985
        plan = list(self.plan_merge_vf.plan_lca_merge(b'E', b'D'))
991
986
        self.assertEqual([
992
 
                          ('unchanged', 'a\n'),
993
 
                          ('unchanged', 'b\n'),
994
 
                          ('unchanged', 'c\n'),
995
 
                          ('unchanged', 'd\n'),
996
 
                          ('conflicted-b', 'g\n'),
997
 
                          ('unchanged', 'h\n'),
998
 
                          ('conflicted-a', 'g\n'),
999
 
                          ('unchanged', 'e\n'),
1000
 
                          ('unchanged', 'f\n'),
 
987
                          ('unchanged', b'a\n'),
 
988
                          ('unchanged', b'b\n'),
 
989
                          ('unchanged', b'c\n'),
 
990
                          ('unchanged', b'd\n'),
 
991
                          ('conflicted-b', b'g\n'),
 
992
                          ('unchanged', b'h\n'),
 
993
                          ('conflicted-a', b'g\n'),
 
994
                          ('unchanged', b'e\n'),
 
995
                          ('unchanged', b'f\n'),
1001
996
                         ], plan)
1002
997
        pwm = versionedfile.PlanWeaveMerge(plan)
1003
 
        self.assertEqualDiff('\n'.join('abcdhef') + '\n',
1004
 
                             ''.join(pwm.base_from_plan()))
 
998
        self.assertEqualDiff(b'\n'.join(b'abcdhef') + b'\n',
 
999
                             b''.join(pwm.base_from_plan()))
1005
1000
 
1006
1001
    def assertRemoveExternalReferences(self, filtered_parent_map,
1007
1002
                                       child_map, tails, parent_map):
1076
1071
 
1077
1072
    def test_subtract_plans(self):
1078
1073
        old_plan = [
1079
 
        ('unchanged', 'a\n'),
1080
 
        ('new-a', 'b\n'),
1081
 
        ('killed-a', 'c\n'),
1082
 
        ('new-b', 'd\n'),
1083
 
        ('new-b', 'e\n'),
1084
 
        ('killed-b', 'f\n'),
1085
 
        ('killed-b', 'g\n'),
 
1074
        ('unchanged', b'a\n'),
 
1075
        ('new-a', b'b\n'),
 
1076
        ('killed-a', b'c\n'),
 
1077
        ('new-b', b'd\n'),
 
1078
        ('new-b', b'e\n'),
 
1079
        ('killed-b', b'f\n'),
 
1080
        ('killed-b', b'g\n'),
1086
1081
        ]
1087
1082
        new_plan = [
1088
 
        ('unchanged', 'a\n'),
1089
 
        ('new-a', 'b\n'),
1090
 
        ('killed-a', 'c\n'),
1091
 
        ('new-b', 'd\n'),
1092
 
        ('new-b', 'h\n'),
1093
 
        ('killed-b', 'f\n'),
1094
 
        ('killed-b', 'i\n'),
 
1083
        ('unchanged', b'a\n'),
 
1084
        ('new-a', b'b\n'),
 
1085
        ('killed-a', b'c\n'),
 
1086
        ('new-b', b'd\n'),
 
1087
        ('new-b', b'h\n'),
 
1088
        ('killed-b', b'f\n'),
 
1089
        ('killed-b', b'i\n'),
1095
1090
        ]
1096
1091
        subtracted_plan = [
1097
 
        ('unchanged', 'a\n'),
1098
 
        ('new-a', 'b\n'),
1099
 
        ('killed-a', 'c\n'),
1100
 
        ('new-b', 'h\n'),
1101
 
        ('unchanged', 'f\n'),
1102
 
        ('killed-b', 'i\n'),
 
1092
        ('unchanged', b'a\n'),
 
1093
        ('new-a', b'b\n'),
 
1094
        ('killed-a', b'c\n'),
 
1095
        ('new-b', b'h\n'),
 
1096
        ('unchanged', b'f\n'),
 
1097
        ('killed-b', b'i\n'),
1103
1098
        ]
1104
1099
        self.assertEqual(subtracted_plan,
1105
1100
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
1106
1101
 
1107
1102
    def setup_merge_with_base(self):
1108
 
        self.add_rev('root', 'COMMON', [], 'abc')
1109
 
        self.add_rev('root', 'THIS', ['COMMON'], 'abcd')
1110
 
        self.add_rev('root', 'BASE', ['COMMON'], 'eabc')
1111
 
        self.add_rev('root', 'OTHER', ['BASE'], 'eafb')
 
1103
        self.add_rev(b'root', b'COMMON', [], b'abc')
 
1104
        self.add_rev(b'root', b'THIS', [b'COMMON'], b'abcd')
 
1105
        self.add_rev(b'root', b'BASE', [b'COMMON'], b'eabc')
 
1106
        self.add_rev(b'root', b'OTHER', [b'BASE'], b'eafb')
1112
1107
 
1113
1108
    def test_plan_merge_with_base(self):
1114
1109
        self.setup_merge_with_base()
1115
 
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
1116
 
        self.assertEqual([('unchanged', 'a\n'),
1117
 
                          ('new-b', 'f\n'),
1118
 
                          ('unchanged', 'b\n'),
1119
 
                          ('killed-b', 'c\n'),
1120
 
                          ('new-a', 'd\n')
 
1110
        plan = self.plan_merge_vf.plan_merge(b'THIS', b'OTHER', b'BASE')
 
1111
        self.assertEqual([('unchanged', b'a\n'),
 
1112
                          ('new-b', b'f\n'),
 
1113
                          ('unchanged', b'b\n'),
 
1114
                          ('killed-b', b'c\n'),
 
1115
                          ('new-a', b'd\n')
1121
1116
                         ], list(plan))
1122
1117
 
1123
1118
    def test_plan_lca_merge(self):
1124
1119
        self.setup_plan_merge()
1125
 
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
 
1120
        plan = self.plan_merge_vf.plan_lca_merge(b'B', b'C')
1126
1121
        self.assertEqual([
1127
 
                          ('new-b', 'f\n'),
1128
 
                          ('unchanged', 'a\n'),
1129
 
                          ('killed-b', 'c\n'),
1130
 
                          ('new-a', 'e\n'),
1131
 
                          ('new-a', 'h\n'),
1132
 
                          ('killed-a', 'b\n'),
1133
 
                          ('unchanged', 'g\n')],
 
1122
                          ('new-b', b'f\n'),
 
1123
                          ('unchanged', b'a\n'),
 
1124
                          ('killed-b', b'c\n'),
 
1125
                          ('new-a', b'e\n'),
 
1126
                          ('new-a', b'h\n'),
 
1127
                          ('killed-a', b'b\n'),
 
1128
                          ('unchanged', b'g\n')],
1134
1129
                         list(plan))
1135
1130
 
1136
1131
    def test_plan_lca_merge_uncommitted_files(self):
1137
1132
        self.setup_plan_merge_uncommitted()
1138
 
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
 
1133
        plan = self.plan_merge_vf.plan_lca_merge(b'B:', b'C:')
1139
1134
        self.assertEqual([
1140
 
                          ('new-b', 'f\n'),
1141
 
                          ('unchanged', 'a\n'),
1142
 
                          ('killed-b', 'c\n'),
1143
 
                          ('new-a', 'e\n'),
1144
 
                          ('new-a', 'h\n'),
1145
 
                          ('killed-a', 'b\n'),
1146
 
                          ('unchanged', 'g\n')],
 
1135
                          ('new-b', b'f\n'),
 
1136
                          ('unchanged', b'a\n'),
 
1137
                          ('killed-b', b'c\n'),
 
1138
                          ('new-a', b'e\n'),
 
1139
                          ('new-a', b'h\n'),
 
1140
                          ('killed-a', b'b\n'),
 
1141
                          ('unchanged', b'g\n')],
1147
1142
                         list(plan))
1148
1143
 
1149
1144
    def test_plan_lca_merge_with_base(self):
1150
1145
        self.setup_merge_with_base()
1151
 
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
1152
 
        self.assertEqual([('unchanged', 'a\n'),
1153
 
                          ('new-b', 'f\n'),
1154
 
                          ('unchanged', 'b\n'),
1155
 
                          ('killed-b', 'c\n'),
1156
 
                          ('new-a', 'd\n')
 
1146
        plan = self.plan_merge_vf.plan_lca_merge(b'THIS', b'OTHER', b'BASE')
 
1147
        self.assertEqual([('unchanged', b'a\n'),
 
1148
                          ('new-b', b'f\n'),
 
1149
                          ('unchanged', b'b\n'),
 
1150
                          ('killed-b', b'c\n'),
 
1151
                          ('new-a', b'd\n')
1157
1152
                         ], list(plan))
1158
1153
 
1159
1154
    def test_plan_lca_merge_with_criss_cross(self):
1160
 
        self.add_version(('root', 'ROOT'), [], 'abc')
 
1155
        self.add_version((b'root', b'ROOT'), [], b'abc')
1161
1156
        # each side makes a change
1162
 
        self.add_version(('root', 'REV1'), [('root', 'ROOT')], 'abcd')
1163
 
        self.add_version(('root', 'REV2'), [('root', 'ROOT')], 'abce')
 
1157
        self.add_version((b'root', b'REV1'), [(b'root', b'ROOT')], b'abcd')
 
1158
        self.add_version((b'root', b'REV2'), [(b'root', b'ROOT')], b'abce')
1164
1159
        # both sides merge, discarding others' changes
1165
 
        self.add_version(('root', 'LCA1'),
1166
 
            [('root', 'REV1'), ('root', 'REV2')], 'abcd')
1167
 
        self.add_version(('root', 'LCA2'),
1168
 
            [('root', 'REV1'), ('root', 'REV2')], 'fabce')
1169
 
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
1170
 
        self.assertEqual([('new-b', 'f\n'),
1171
 
                          ('unchanged', 'a\n'),
1172
 
                          ('unchanged', 'b\n'),
1173
 
                          ('unchanged', 'c\n'),
1174
 
                          ('conflicted-a', 'd\n'),
1175
 
                          ('conflicted-b', 'e\n'),
 
1160
        self.add_version((b'root', b'LCA1'),
 
1161
            [(b'root', b'REV1'), (b'root', b'REV2')], b'abcd')
 
1162
        self.add_version((b'root', b'LCA2'),
 
1163
            [(b'root', b'REV1'), (b'root', b'REV2')], b'fabce')
 
1164
        plan = self.plan_merge_vf.plan_lca_merge(b'LCA1', b'LCA2')
 
1165
        self.assertEqual([('new-b', b'f\n'),
 
1166
                          ('unchanged', b'a\n'),
 
1167
                          ('unchanged', b'b\n'),
 
1168
                          ('unchanged', b'c\n'),
 
1169
                          ('conflicted-a', b'd\n'),
 
1170
                          ('conflicted-b', b'e\n'),
1176
1171
                         ], list(plan))
1177
1172
 
1178
1173
    def test_plan_lca_merge_with_null(self):
1179
 
        self.add_version(('root', 'A'), [], 'ab')
1180
 
        self.add_version(('root', 'B'), [], 'bc')
1181
 
        plan = self.plan_merge_vf.plan_lca_merge('A', 'B')
1182
 
        self.assertEqual([('new-a', 'a\n'),
1183
 
                          ('unchanged', 'b\n'),
1184
 
                          ('new-b', 'c\n'),
 
1174
        self.add_version((b'root', b'A'), [], b'ab')
 
1175
        self.add_version((b'root', b'B'), [], b'bc')
 
1176
        plan = self.plan_merge_vf.plan_lca_merge(b'A', b'B')
 
1177
        self.assertEqual([('new-a', b'a\n'),
 
1178
                          ('unchanged', b'b\n'),
 
1179
                          ('new-b', b'c\n'),
1185
1180
                         ], list(plan))
1186
1181
 
1187
1182
    def test_plan_merge_with_delete_and_change(self):
1188
 
        self.add_rev('root', 'C', [], 'a')
1189
 
        self.add_rev('root', 'A', ['C'], 'b')
1190
 
        self.add_rev('root', 'B', ['C'], '')
1191
 
        plan = self.plan_merge_vf.plan_merge('A', 'B')
1192
 
        self.assertEqual([('killed-both', 'a\n'),
1193
 
                          ('new-a', 'b\n'),
 
1183
        self.add_rev(b'root', b'C', [], b'a')
 
1184
        self.add_rev(b'root', b'A', [b'C'], b'b')
 
1185
        self.add_rev(b'root', b'B', [b'C'], b'')
 
1186
        plan = self.plan_merge_vf.plan_merge(b'A', b'B')
 
1187
        self.assertEqual([('killed-both', b'a\n'),
 
1188
                          ('new-a', b'b\n'),
1194
1189
                         ], list(plan))
1195
1190
 
1196
1191
    def test_plan_merge_with_move_and_change(self):
1197
 
        self.add_rev('root', 'C', [], 'abcd')
1198
 
        self.add_rev('root', 'A', ['C'], 'acbd')
1199
 
        self.add_rev('root', 'B', ['C'], 'aBcd')
1200
 
        plan = self.plan_merge_vf.plan_merge('A', 'B')
1201
 
        self.assertEqual([('unchanged', 'a\n'),
1202
 
                          ('new-a', 'c\n'),
1203
 
                          ('killed-b', 'b\n'),
1204
 
                          ('new-b', 'B\n'),
1205
 
                          ('killed-a', 'c\n'),
1206
 
                          ('unchanged', 'd\n'),
 
1192
        self.add_rev(b'root', b'C', [], b'abcd')
 
1193
        self.add_rev(b'root', b'A', [b'C'], b'acbd')
 
1194
        self.add_rev(b'root', b'B', [b'C'], b'aBcd')
 
1195
        plan = self.plan_merge_vf.plan_merge(b'A', b'B')
 
1196
        self.assertEqual([('unchanged', b'a\n'),
 
1197
                          ('new-a', b'c\n'),
 
1198
                          ('killed-b', b'b\n'),
 
1199
                          ('new-b', b'B\n'),
 
1200
                          ('killed-a', b'c\n'),
 
1201
                          ('unchanged', b'd\n'),
1207
1202
                         ], list(plan))
1208
1203
 
1209
1204
 
1403
1398
        builder = self.get_builder()
1404
1399
        builder.build_snapshot(None,
1405
1400
            [('add', (u'', b'a-root-id', 'directory', None)),
1406
 
             ('add', (u'a', b'a-id', 'file', 'a\nb\nc\n'))],
 
1401
             ('add', (u'a', b'a-id', 'file', b'a\nb\nc\n'))],
1407
1402
            revision_id=b'A-id')
1408
1403
        builder.build_snapshot([b'A-id'],
1409
1404
            [('modify', ('a', b'a\nb\nC\nc\n'))],
1833
1828
            [('modify', ('foo', b'B content\n'))],
1834
1829
            revision_id=b'B-id')
1835
1830
        builder.build_snapshot([b'A-id'],
1836
 
            [('modify', ('foo', 'C content\n'))],
 
1831
            [('modify', ('foo', b'C content\n'))],
1837
1832
            revision_id=b'C-id')
1838
1833
        builder.build_snapshot([b'C-id', b'B-id'], [], revision_id=b'E-id')
1839
1834
        builder.build_snapshot([b'B-id', b'C-id'], [], revision_id=b'D-id')
1865
1860
             ('add', (u'foo', b'foo-id', 'file', b'A content\n'))],
1866
1861
            revision_id=b'A-id')
1867
1862
        builder.build_snapshot([b'A-id'],
1868
 
            [('modify', ('foo', 'B content\n'))],
 
1863
            [('modify', ('foo', b'B content\n'))],
1869
1864
            revision_id=b'B-id')
1870
1865
        builder.build_snapshot([b'A-id'],
1871
1866
            [('modify', ('foo', b'C content\n'))],
2031
2026
        builder.build_snapshot([b'A-id'], [], revision_id=b'B-id')
2032
2027
        builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
2033
2028
        builder.build_snapshot([b'C-id', b'B-id'],
2034
 
            [('modify', ('a', 'new-content\n')),
2035
 
             ('modify', ('b', 'new-content\n'))],
 
2029
            [('modify', ('a', b'new-content\n')),
 
2030
             ('modify', ('b', b'new-content\n'))],
2036
2031
            revision_id=b'E-id')
2037
2032
        builder.build_snapshot([b'B-id', b'C-id'],
2038
2033
            [('rename', ('b', 'c'))],
2626
2621
        builder = self.get_builder()
2627
2622
        builder.build_snapshot(None,
2628
2623
            [('add', (u'', b'a-root-id', 'directory', None)),
2629
 
             ('add', (u'foo', b'foo-id', 'file', 'a\nb\nc\n'))],
 
2624
             ('add', (u'foo', b'foo-id', 'file', b'a\nb\nc\n'))],
2630
2625
            revision_id=b'A-id')
2631
2626
        builder.build_snapshot([b'A-id'], [], revision_id=b'C-id')
2632
2627
        builder.build_snapshot([b'A-id'],
2764
2759
        wt.set_last_revision(b'A-id')
2765
2760
        wt.branch.set_last_revision_info(1, b'A-id')
2766
2761
        wt.commit('C', rev_id=b'C-id', recursive=None)
2767
 
        wt.merge_from_branch(wt.branch, to_revision='B-id')
 
2762
        wt.merge_from_branch(wt.branch, to_revision=b'B-id')
2768
2763
        wt.commit('E', rev_id=b'E-id', recursive=None)
2769
2764
        wt.set_parent_ids([b'B-id', b'C-id'])
2770
2765
        wt.branch.set_last_revision_info(2, b'B-id')
2798
2793
        wt.set_last_revision(b'A-id')
2799
2794
        wt.branch.set_last_revision_info(1, b'A-id')
2800
2795
        wt.commit('C', rev_id=b'C-id', recursive=None)
2801
 
        wt.merge_from_branch(wt.branch, to_revision='B-id')
 
2796
        wt.merge_from_branch(wt.branch, to_revision=b'B-id')
2802
2797
        self.build_tree_contents([('tree/sub/file', b'text2')])
2803
2798
        sub_tree.commit('modify contents', rev_id=b'sub-B-id')
2804
2799
        wt.commit('E', rev_id=b'E-id', recursive=None)
2850
2845
        merge_obj = merger.make_merger()
2851
2846
        entries = list(merge_obj._entries_lca())
2852
2847
        root_id = b'a-root-id'
2853
 
        self.assertEqual([('sub-tree-root', False,
 
2848
        self.assertEqual([(b'sub-tree-root', False,
2854
2849
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2855
2850
                           ((root_id, [root_id, root_id]), root_id, root_id),
2856
2851
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2879
2874
        wt.set_last_revision(b'A-id')
2880
2875
        wt.branch.set_last_revision_info(1, b'A-id')
2881
2876
        wt.commit('C', rev_id=b'C-id', recursive=None)
2882
 
        wt.merge_from_branch(wt.branch, to_revision='B-id')
 
2877
        wt.merge_from_branch(wt.branch, to_revision=b'B-id')
2883
2878
        self.build_tree_contents([('tree/sub/file', b'text2')])
2884
2879
        sub_tree.commit('modify contents', rev_id=b'sub-B-id')
2885
2880
        wt.rename_one('sub', 'alt_sub')
3129
3124
        Default is empty tree (just root entry).
3130
3125
        """
3131
3126
        if root_id is None:
3132
 
            root_id = ('%s-root-id' % (relpath,)).encode('ascii')
 
3127
            root_id = b'%s-root-id' % (relpath.encode('ascii'),)
3133
3128
        wt = self.make_branch_and_tree(relpath)
3134
3129
        wt.set_root_id(root_id)
3135
3130
        if shape is not None:
3136
3131
            adjusted_shape = [relpath + '/' + elem for elem in shape]
3137
3132
            self.build_tree(adjusted_shape)
3138
3133
            ids = [
3139
 
                ('%s-%s-id' % (relpath, basename(elem.rstrip('/')))).encode('ascii')
 
3134
                (b'%s-%s-id' % (relpath.encode('utf-8'), basename(elem.rstrip('/')).encode('ascii')))
3140
3135
                for elem in shape]
3141
3136
            wt.add(shape, ids=ids)
3142
 
        rev_id = 'r1-%s' % (relpath,)
 
3137
        rev_id = b'r1-%s' % (relpath.encode('utf-8'),)
3143
3138
        wt.commit("Initial commit of %s" % (relpath,), rev_id=rev_id)
3144
3139
        self.assertEqual(root_id, wt.path2id(''))
3145
3140
        return wt
3205
3200
        project_wt.lock_read()
3206
3201
        self.addCleanup(project_wt.unlock)
3207
3202
        # The r1-lib1 revision should be merged into this one
3208
 
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
 
3203
        self.assertEqual([b'r1-project', b'r1-lib1'], project_wt.get_parent_ids())
3209
3204
        self.assertTreeEntriesEqual(
3210
 
            [('', 'project-root-id'),
3211
 
             ('README', 'project-README-id'),
3212
 
             ('dir', 'project-dir-id'),
3213
 
             ('lib1', 'lib1-root-id'),
3214
 
             ('dir/file.c', 'project-file.c-id'),
3215
 
             ('lib1/Makefile', 'lib1-Makefile-id'),
3216
 
             ('lib1/README', 'lib1-README-id'),
3217
 
             ('lib1/foo.c', 'lib1-foo.c-id'),
 
3205
            [('', b'project-root-id'),
 
3206
             ('README', b'project-README-id'),
 
3207
             ('dir', b'project-dir-id'),
 
3208
             ('lib1', b'lib1-root-id'),
 
3209
             ('dir/file.c', b'project-file.c-id'),
 
3210
             ('lib1/Makefile', b'lib1-Makefile-id'),
 
3211
             ('lib1/README', b'lib1-README-id'),
 
3212
             ('lib1/foo.c', b'lib1-foo.c-id'),
3218
3213
            ], project_wt)
3219
3214
 
3220
3215
    def test_subdir(self):
3224
3219
        project_wt.lock_read()
3225
3220
        self.addCleanup(project_wt.unlock)
3226
3221
        # The r1-lib1 revision should be merged into this one
3227
 
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
 
3222
        self.assertEqual([b'r1-project', b'r1-lib1'], project_wt.get_parent_ids())
3228
3223
        self.assertTreeEntriesEqual(
3229
 
            [('', 'project-root-id'),
3230
 
             ('README', 'project-README-id'),
3231
 
             ('dir', 'project-dir-id'),
3232
 
             ('dir/file.c', 'project-file.c-id'),
3233
 
             ('dir/lib1', 'lib1-root-id'),
3234
 
             ('dir/lib1/Makefile', 'lib1-Makefile-id'),
3235
 
             ('dir/lib1/README', 'lib1-README-id'),
3236
 
             ('dir/lib1/foo.c', 'lib1-foo.c-id'),
 
3224
            [('', b'project-root-id'),
 
3225
             ('README', b'project-README-id'),
 
3226
             ('dir', b'project-dir-id'),
 
3227
             ('dir/file.c', b'project-file.c-id'),
 
3228
             ('dir/lib1', b'lib1-root-id'),
 
3229
             ('dir/lib1/Makefile', b'lib1-Makefile-id'),
 
3230
             ('dir/lib1/README', b'lib1-README-id'),
 
3231
             ('dir/lib1/foo.c', b'lib1-foo.c-id'),
3237
3232
            ], project_wt)
3238
3233
 
3239
3234
    def test_newdir_with_repeat_roots(self):
3246
3241
        project_wt.lock_read()
3247
3242
        self.addCleanup(project_wt.unlock)
3248
3243
        # The r1-lib1 revision should be merged into this one
3249
 
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
 
3244
        self.assertEqual([b'r1-project', b'r1-lib1'], project_wt.get_parent_ids())
3250
3245
        new_lib1_id = project_wt.path2id('lib1')
3251
3246
        self.assertNotEqual(None, new_lib1_id)
3252
3247
        self.assertTreeEntriesEqual(
3253
3248
            [('', root_id),
3254
 
             ('README', 'project-README-id'),
3255
 
             ('dir', 'project-dir-id'),
 
3249
             ('README', b'project-README-id'),
 
3250
             ('dir', b'project-dir-id'),
3256
3251
             ('lib1', new_lib1_id),
3257
 
             ('dir/file.c', 'project-file.c-id'),
3258
 
             ('lib1/Makefile', 'lib1-Makefile-id'),
3259
 
             ('lib1/README', 'lib1-README-id'),
3260
 
             ('lib1/foo.c', 'lib1-foo.c-id'),
 
3252
             ('dir/file.c', b'project-file.c-id'),
 
3253
             ('lib1/Makefile', b'lib1-Makefile-id'),
 
3254
             ('lib1/README', b'lib1-README-id'),
 
3255
             ('lib1/foo.c', b'lib1-foo.c-id'),
3261
3256
            ], project_wt)
3262
3257
 
3263
3258
    def test_name_conflict(self):
3271
3266
        dest_wt.lock_read()
3272
3267
        self.addCleanup(dest_wt.unlock)
3273
3268
        # The r1-lib1 revision should be merged into this one
3274
 
        self.assertEqual(['r1-dest', 'r1-src'], dest_wt.get_parent_ids())
 
3269
        self.assertEqual([b'r1-dest', b'r1-src'], dest_wt.get_parent_ids())
3275
3270
        self.assertTreeEntriesEqual(
3276
 
            [('', 'dest-root-id'),
3277
 
             ('dir', 'src-root-id'),
3278
 
             ('dir.moved', 'dest-dir-id'),
3279
 
             ('dir/README', 'src-README-id'),
3280
 
             ('dir.moved/file.txt', 'dest-file.txt-id'),
 
3271
            [('', b'dest-root-id'),
 
3272
             ('dir', b'src-root-id'),
 
3273
             ('dir.moved', b'dest-dir-id'),
 
3274
             ('dir/README', b'src-README-id'),
 
3275
             ('dir.moved/file.txt', b'dest-file.txt-id'),
3281
3276
            ], dest_wt)
3282
3277
 
3283
3278
    def test_file_id_conflict(self):
3309
3304
        self.addCleanup(dest_wt.unlock)
3310
3305
        # The r1-lib1 revision should NOT be merged into this one (this is a
3311
3306
        # partial merge).
3312
 
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
 
3307
        self.assertEqual([b'r1-dest'], dest_wt.get_parent_ids())
3313
3308
        self.assertTreeEntriesEqual(
3314
 
            [('', 'dest-root-id'),
3315
 
             ('dir', 'src-dir-id'),
3316
 
             ('dir/foo.c', 'src-foo.c-id'),
 
3309
            [('', b'dest-root-id'),
 
3310
             ('dir', b'src-dir-id'),
 
3311
             ('dir/foo.c', b'src-foo.c-id'),
3317
3312
            ], dest_wt)
3318
3313
 
3319
3314
    def test_only_file(self):
3325
3320
        dest_wt.lock_read()
3326
3321
        self.addCleanup(dest_wt.unlock)
3327
3322
        # The r1-lib1 revision should NOT be merged into this one
3328
 
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
 
3323
        self.assertEqual([b'r1-dest'], dest_wt.get_parent_ids())
3329
3324
        self.assertTreeEntriesEqual(
3330
 
            [('', 'dest-root-id'), ('file1.txt', 'two-file-file1.txt-id')],
 
3325
            [('', b'dest-root-id'), ('file1.txt', b'two-file-file1.txt-id')],
3331
3326
            dest_wt)
3332
3327
 
3333
3328
    def test_no_such_source_path(self):
3341
3336
        dest_wt.lock_read()
3342
3337
        self.addCleanup(dest_wt.unlock)
3343
3338
        # The dest tree is unmodified.
3344
 
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3345
 
        self.assertTreeEntriesEqual([('', 'dest-root-id')], dest_wt)
 
3339
        self.assertEqual([b'r1-dest'], dest_wt.get_parent_ids())
 
3340
        self.assertTreeEntriesEqual([('', b'dest-root-id')], dest_wt)
3346
3341
 
3347
3342
    def test_no_such_target_path(self):
3348
3343
        """PathNotInTree is also raised if the specified path in the target
3355
3350
        dest_wt.lock_read()
3356
3351
        self.addCleanup(dest_wt.unlock)
3357
3352
        # The dest tree is unmodified.
3358
 
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3359
 
        self.assertTreeEntriesEqual([('', 'dest-root-id')], dest_wt)
 
3353
        self.assertEqual([b'r1-dest'], dest_wt.get_parent_ids())
 
3354
        self.assertTreeEntriesEqual([('', b'dest-root-id')], dest_wt)
3360
3355
 
3361
3356
 
3362
3357
class TestMergeHooks(TestCaseWithTransport):
3385
3380
                                                   factory, 'test factory')
3386
3381
        self.tree_a.merge_from_branch(self.tree_b.branch)
3387
3382
 
3388
 
        self.assertFileEqual("content_3", 'tree_a/file')
 
3383
        self.assertFileEqual(b"content_3", 'tree_a/file')
3389
3384
        self.assertLength(1, calls)
3390
3385
 
3391
3386
    def test_post_merge_hook_called(self):
3398
3393
 
3399
3394
        self.tree_a.merge_from_branch(self.tree_b.branch)
3400
3395
 
3401
 
        self.assertFileEqual("content_2", 'tree_a/file')
 
3396
        self.assertFileEqual(b"content_2", 'tree_a/file')
3402
3397
        self.assertLength(1, calls)