/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_merge.py

  • Committer: John Arbash Meinel
  • Date: 2009-06-17 19:08:25 UTC
  • mto: This revision was merged to the branch mainline in revision 4460.
  • Revision ID: john@arbash-meinel.com-20090617190825-ktfk82li57rf2im6
It seems that fetch() no longer returns the number of revisions fetched.
It still does for *some* InterRepository fetch paths, but the generic one does not.
It is also not easy to get it to, since the Source and Sink are the ones
that would know how many keys were transmitted, and they are potentially 'remote'
objects.

This was also only tested to occur as a by-product in a random 'test_commit' test.
I assume if we really wanted the assurance, we would have a per_repo or interrepo
test for it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
29
29
    transform,
30
30
    versionedfile,
31
31
    )
 
32
from bzrlib.branch import Branch
32
33
from bzrlib.conflicts import ConflictList, TextConflict
33
 
from bzrlib.errors import UnrelatedBranches, NoCommits
 
34
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
34
35
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
35
36
from bzrlib.osutils import pathjoin, file_kind
36
 
from bzrlib.tests import (
37
 
    TestCaseWithMemoryTransport,
38
 
    TestCaseWithTransport,
39
 
    test_merge_core,
40
 
    )
 
37
from bzrlib.tests import TestCaseWithTransport, TestCaseWithMemoryTransport
41
38
from bzrlib.workingtree import WorkingTree
42
39
 
43
40
 
154
151
        log = StringIO()
155
152
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
156
153
                    this_tree=tree_b, ignore_zero=True)
157
 
        self.failUnless('All changes applied successfully.\n' not in
158
 
            self.get_log())
 
154
        log = self._get_log(keep_log_file=True)
 
155
        self.failUnless('All changes applied successfully.\n' not in log)
159
156
        tree_b.revert()
160
157
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
161
158
                    this_tree=tree_b, ignore_zero=False)
162
 
        self.failUnless('All changes applied successfully.\n' in self.get_log())
 
159
        log = self._get_log(keep_log_file=True)
 
160
        self.failUnless('All changes applied successfully.\n' in log)
163
161
 
164
162
    def test_merge_inner_conflicts(self):
165
163
        tree_a = self.make_branch_and_tree('a')
220
218
        tree_a.add('file')
221
219
        tree_a.commit('commit base')
222
220
        # basis_tree() is only guaranteed to be valid as long as it is actually
223
 
        # the basis tree. This test commits to the tree after grabbing basis,
224
 
        # so we go to the repository.
 
221
        # the basis tree. This mutates the tree after grabbing basis, so go to
 
222
        # the repository.
225
223
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
226
224
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
227
225
        self.build_tree_contents([('tree_a/file', 'content_2')])
228
226
        tree_a.commit('commit other')
229
227
        other_tree = tree_a.basis_tree()
230
 
        # 'file' is now missing but isn't altered in any commit in b so no
231
 
        # change should be applied.
232
228
        os.unlink('tree_b/file')
233
229
        merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b)
234
230
 
295
291
        tree_a.commit('commit 2')
296
292
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
297
293
        tree_b.rename_one('file_1', 'renamed')
298
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
 
294
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
 
295
                                                    progress.DummyProgress())
299
296
        merger.merge_type = _mod_merge.Merge3Merger
300
297
        merger.do_merge()
301
298
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
309
306
        tree_a.commit('commit 2')
310
307
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
311
308
        tree_b.rename_one('file_1', 'renamed')
312
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
 
309
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
 
310
                                                    progress.DummyProgress())
313
311
        merger.merge_type = _mod_merge.WeaveMerger
314
312
        merger.do_merge()
315
313
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
316
314
 
 
315
    def test_Merger_defaults_to_DummyProgress(self):
 
316
        branch = self.make_branch('branch')
 
317
        merger = _mod_merge.Merger(branch, pb=None)
 
318
        self.assertIsInstance(merger._pb, progress.DummyProgress)
 
319
 
317
320
    def prepare_cherrypick(self):
318
321
        """Prepare a pair of trees for cherrypicking tests.
319
322
 
340
343
 
341
344
    def test_weave_cherrypick(self):
342
345
        this_tree, other_tree = self.prepare_cherrypick()
343
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
346
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
344
347
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
345
348
        merger.merge_type = _mod_merge.WeaveMerger
346
349
        merger.do_merge()
348
351
 
349
352
    def test_weave_cannot_reverse_cherrypick(self):
350
353
        this_tree, other_tree = self.prepare_cherrypick()
351
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
354
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
352
355
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
353
356
        merger.merge_type = _mod_merge.WeaveMerger
354
357
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
355
358
 
356
359
    def test_merge3_can_reverse_cherrypick(self):
357
360
        this_tree, other_tree = self.prepare_cherrypick()
358
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
361
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
359
362
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
360
363
        merger.merge_type = _mod_merge.Merge3Merger
361
364
        merger.do_merge()
373
376
        this_tree.lock_write()
374
377
        self.addCleanup(this_tree.unlock)
375
378
 
376
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
379
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
377
380
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
378
381
        merger.merge_type = _mod_merge.Merge3Merger
379
382
        merger.do_merge()
392
395
        other_tree.commit('rev2', rev_id='rev2b')
393
396
        this_tree.lock_write()
394
397
        self.addCleanup(this_tree.unlock)
395
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
398
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress,
396
399
            this_tree, 'rev2b', other_branch=other_tree.branch)
397
400
        merger.merge_type = _mod_merge.Merge3Merger
398
401
        tree_merger = merger.make_merger()
412
415
        other_tree.commit('rev2', rev_id='rev2b')
413
416
        this_tree.lock_write()
414
417
        self.addCleanup(this_tree.unlock)
415
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
418
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
416
419
            this_tree, 'rev2b', other_branch=other_tree.branch)
417
420
        merger.merge_type = _mod_merge.Merge3Merger
418
421
        tree_merger = merger.make_merger()
442
445
        other_tree.commit('rev2', rev_id='rev2b')
443
446
        this_tree.lock_write()
444
447
        self.addCleanup(this_tree.unlock)
445
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
448
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
446
449
            this_tree, 'rev2b', other_branch=other_tree.branch)
447
450
        merger.merge_type = _mod_merge.Merge3Merger
448
451
        tree_merger = merger.make_merger()
519
522
        self.add_uncommitted_version(('root', 'C:'), [('root', 'A')], 'fabg')
520
523
        return _PlanMerge('B:', 'C:', self.plan_merge_vf, ('root',))
521
524
 
522
 
    def test_base_from_plan(self):
523
 
        self.setup_plan_merge()
524
 
        plan = self.plan_merge_vf.plan_merge('B', 'C')
525
 
        pwm = versionedfile.PlanWeaveMerge(plan)
526
 
        self.assertEqual(['a\n', 'b\n', 'c\n'], pwm.base_from_plan())
527
 
 
528
525
    def test_unique_lines(self):
529
526
        plan = self.setup_plan_merge()
530
527
        self.assertEqual(plan._unique_lines(
828
825
                          ('unchanged', 'f\n'),
829
826
                          ('unchanged', 'g\n')],
830
827
                         list(plan))
831
 
        plan = self.plan_merge_vf.plan_lca_merge('F', 'G')
832
 
        # This is one of the main differences between plan_merge and
833
 
        # plan_lca_merge. plan_lca_merge generates a conflict for 'x => z',
834
 
        # because 'x' was not present in one of the bases. However, in this
835
 
        # case it is spurious because 'x' does not exist in the global base A.
836
 
        self.assertEqual([
837
 
                          ('unchanged', 'h\n'),
838
 
                          ('unchanged', 'a\n'),
839
 
                          ('conflicted-a', 'x\n'),
840
 
                          ('new-b', 'z\n'),
841
 
                          ('unchanged', 'c\n'),
842
 
                          ('unchanged', 'd\n'),
843
 
                          ('unchanged', 'y\n'),
844
 
                          ('unchanged', 'f\n'),
845
 
                          ('unchanged', 'g\n')],
846
 
                         list(plan))
847
 
 
848
 
    def test_criss_cross_flip_flop(self):
849
 
        # This is specificly trying to trigger problems when using limited
850
 
        # ancestry and weaves. The ancestry graph looks like:
851
 
        #       XX      unused ancestor, should not show up in the weave
852
 
        #       |
853
 
        #       A       Unique LCA
854
 
        #      / \  
855
 
        #     B   C     B & C both introduce a new line
856
 
        #     |\ /|  
857
 
        #     | X |  
858
 
        #     |/ \| 
859
 
        #     D   E     B & C are both merged, so both are common ancestors
860
 
        #               In the process of merging, both sides order the new
861
 
        #               lines differently
862
 
        #
863
 
        self.add_rev('root', 'XX', [], 'qrs')
864
 
        self.add_rev('root', 'A', ['XX'], 'abcdef')
865
 
        self.add_rev('root', 'B', ['A'], 'abcdgef')
866
 
        self.add_rev('root', 'C', ['A'], 'abcdhef')
867
 
        self.add_rev('root', 'D', ['B', 'C'], 'abcdghef')
868
 
        self.add_rev('root', 'E', ['C', 'B'], 'abcdhgef')
869
 
        plan = list(self.plan_merge_vf.plan_merge('D', 'E'))
870
 
        self.assertEqual([
871
 
                          ('unchanged', 'a\n'),
872
 
                          ('unchanged', 'b\n'),
873
 
                          ('unchanged', 'c\n'),
874
 
                          ('unchanged', 'd\n'),
875
 
                          ('new-b', 'h\n'),
876
 
                          ('unchanged', 'g\n'),
877
 
                          ('killed-b', 'h\n'),
878
 
                          ('unchanged', 'e\n'),
879
 
                          ('unchanged', 'f\n'),
880
 
                         ], plan)
881
 
        pwm = versionedfile.PlanWeaveMerge(plan)
882
 
        self.assertEqualDiff('\n'.join('abcdghef') + '\n',
883
 
                             ''.join(pwm.base_from_plan()))
884
 
        # Reversing the order reverses the merge plan, and final order of 'hg'
885
 
        # => 'gh'
886
 
        plan = list(self.plan_merge_vf.plan_merge('E', 'D'))
887
 
        self.assertEqual([
888
 
                          ('unchanged', 'a\n'),
889
 
                          ('unchanged', 'b\n'),
890
 
                          ('unchanged', 'c\n'),
891
 
                          ('unchanged', 'd\n'),
892
 
                          ('new-b', 'g\n'),
893
 
                          ('unchanged', 'h\n'),
894
 
                          ('killed-b', 'g\n'),
895
 
                          ('unchanged', 'e\n'),
896
 
                          ('unchanged', 'f\n'),
897
 
                         ], plan)
898
 
        pwm = versionedfile.PlanWeaveMerge(plan)
899
 
        self.assertEqualDiff('\n'.join('abcdhgef') + '\n',
900
 
                             ''.join(pwm.base_from_plan()))
901
 
        # This is where lca differs, in that it (fairly correctly) determines
902
 
        # that there is a conflict because both sides resolved the merge
903
 
        # differently
904
 
        plan = list(self.plan_merge_vf.plan_lca_merge('D', 'E'))
905
 
        self.assertEqual([
906
 
                          ('unchanged', 'a\n'),
907
 
                          ('unchanged', 'b\n'),
908
 
                          ('unchanged', 'c\n'),
909
 
                          ('unchanged', 'd\n'),
910
 
                          ('conflicted-b', 'h\n'),
911
 
                          ('unchanged', 'g\n'),
912
 
                          ('conflicted-a', 'h\n'),
913
 
                          ('unchanged', 'e\n'),
914
 
                          ('unchanged', 'f\n'),
915
 
                         ], plan)
916
 
        pwm = versionedfile.PlanWeaveMerge(plan)
917
 
        self.assertEqualDiff('\n'.join('abcdgef') + '\n',
918
 
                             ''.join(pwm.base_from_plan()))
919
 
        # Reversing it changes what line is doubled, but still gives a
920
 
        # double-conflict
921
 
        plan = list(self.plan_merge_vf.plan_lca_merge('E', 'D'))
922
 
        self.assertEqual([
923
 
                          ('unchanged', 'a\n'),
924
 
                          ('unchanged', 'b\n'),
925
 
                          ('unchanged', 'c\n'),
926
 
                          ('unchanged', 'd\n'),
927
 
                          ('conflicted-b', 'g\n'),
928
 
                          ('unchanged', 'h\n'),
929
 
                          ('conflicted-a', 'g\n'),
930
 
                          ('unchanged', 'e\n'),
931
 
                          ('unchanged', 'f\n'),
932
 
                         ], plan)
933
 
        pwm = versionedfile.PlanWeaveMerge(plan)
934
 
        self.assertEqualDiff('\n'.join('abcdhef') + '\n',
935
 
                             ''.join(pwm.base_from_plan()))
936
828
 
937
829
    def assertRemoveExternalReferences(self, filtered_parent_map,
938
830
                                       child_map, tails, parent_map):
1138
1030
                         ], list(plan))
1139
1031
 
1140
1032
 
 
1033
class TestMergeImplementation(object):
 
1034
 
 
1035
    def do_merge(self, target_tree, source_tree, **kwargs):
 
1036
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
 
1037
            target_tree, source_tree.last_revision(),
 
1038
            other_branch=source_tree.branch)
 
1039
        merger.merge_type=self.merge_type
 
1040
        for name, value in kwargs.items():
 
1041
            setattr(merger, name, value)
 
1042
        merger.do_merge()
 
1043
 
 
1044
    def test_merge_specific_file(self):
 
1045
        this_tree = self.make_branch_and_tree('this')
 
1046
        this_tree.lock_write()
 
1047
        self.addCleanup(this_tree.unlock)
 
1048
        self.build_tree_contents([
 
1049
            ('this/file1', 'a\nb\n'),
 
1050
            ('this/file2', 'a\nb\n')
 
1051
        ])
 
1052
        this_tree.add(['file1', 'file2'])
 
1053
        this_tree.commit('Added files')
 
1054
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
1055
        self.build_tree_contents([
 
1056
            ('other/file1', 'a\nb\nc\n'),
 
1057
            ('other/file2', 'a\nb\nc\n')
 
1058
        ])
 
1059
        other_tree.commit('modified both')
 
1060
        self.build_tree_contents([
 
1061
            ('this/file1', 'd\na\nb\n'),
 
1062
            ('this/file2', 'd\na\nb\n')
 
1063
        ])
 
1064
        this_tree.commit('modified both')
 
1065
        self.do_merge(this_tree, other_tree, interesting_files=['file1'])
 
1066
        self.assertFileEqual('d\na\nb\nc\n', 'this/file1')
 
1067
        self.assertFileEqual('d\na\nb\n', 'this/file2')
 
1068
 
 
1069
    def test_merge_move_and_change(self):
 
1070
        this_tree = self.make_branch_and_tree('this')
 
1071
        this_tree.lock_write()
 
1072
        self.addCleanup(this_tree.unlock)
 
1073
        self.build_tree_contents([
 
1074
            ('this/file1', 'line 1\nline 2\nline 3\nline 4\n'),
 
1075
        ])
 
1076
        this_tree.add('file1',)
 
1077
        this_tree.commit('Added file')
 
1078
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
1079
        self.build_tree_contents([
 
1080
            ('other/file1', 'line 1\nline 2 to 2.1\nline 3\nline 4\n'),
 
1081
        ])
 
1082
        other_tree.commit('Changed 2 to 2.1')
 
1083
        self.build_tree_contents([
 
1084
            ('this/file1', 'line 1\nline 3\nline 2\nline 4\n'),
 
1085
        ])
 
1086
        this_tree.commit('Swapped 2 & 3')
 
1087
        self.do_merge(this_tree, other_tree)
 
1088
        self.assertFileEqual('line 1\n'
 
1089
            '<<<<<<< TREE\n'
 
1090
            'line 3\n'
 
1091
            'line 2\n'
 
1092
            '=======\n'
 
1093
            'line 2 to 2.1\n'
 
1094
            'line 3\n'
 
1095
            '>>>>>>> MERGE-SOURCE\n'
 
1096
            'line 4\n', 'this/file1')
 
1097
 
 
1098
    def test_modify_conflicts_with_delete(self):
 
1099
        # If one side deletes a line, and the other modifies that line, then
 
1100
        # the modification should be considered a conflict
 
1101
        builder = self.make_branch_builder('test')
 
1102
        builder.start_series()
 
1103
        builder.build_snapshot('BASE-id', None,
 
1104
            [('add', ('', None, 'directory', None)),
 
1105
             ('add', ('foo', 'foo-id', 'file', 'a\nb\nc\nd\ne\n')),
 
1106
            ])
 
1107
        # Delete 'b\n'
 
1108
        builder.build_snapshot('OTHER-id', ['BASE-id'],
 
1109
            [('modify', ('foo-id', 'a\nc\nd\ne\n'))])
 
1110
        # Modify 'b\n', add 'X\n'
 
1111
        builder.build_snapshot('THIS-id', ['BASE-id'],
 
1112
            [('modify', ('foo-id', 'a\nb2\nc\nd\nX\ne\n'))])
 
1113
        builder.finish_series()
 
1114
        branch = builder.get_branch()
 
1115
        this_tree = branch.bzrdir.create_workingtree()
 
1116
        this_tree.lock_write()
 
1117
        self.addCleanup(this_tree.unlock)
 
1118
        other_tree = this_tree.bzrdir.sprout('other', 'OTHER-id').open_workingtree()
 
1119
        self.do_merge(this_tree, other_tree)
 
1120
        if self.merge_type is _mod_merge.LCAMerger:
 
1121
            self.expectFailure("lca merge doesn't track deleted lines",
 
1122
                self.assertFileEqual,
 
1123
                    'a\n'
 
1124
                    '<<<<<<< TREE\n'
 
1125
                    'b2\n'
 
1126
                    '=======\n'
 
1127
                    '>>>>>>> MERGE-SOURCE\n'
 
1128
                    'c\n'
 
1129
                    'd\n'
 
1130
                    'X\n'
 
1131
                    'e\n', 'test/foo')
 
1132
        else:
 
1133
            self.assertFileEqual(
 
1134
                'a\n'
 
1135
                '<<<<<<< TREE\n'
 
1136
                'b2\n'
 
1137
                '=======\n'
 
1138
                '>>>>>>> MERGE-SOURCE\n'
 
1139
                'c\n'
 
1140
                'd\n'
 
1141
                'X\n'
 
1142
                'e\n', 'test/foo')
 
1143
 
 
1144
 
 
1145
class TestMerge3Merge(TestCaseWithTransport, TestMergeImplementation):
 
1146
 
 
1147
    merge_type = _mod_merge.Merge3Merger
 
1148
 
 
1149
 
 
1150
class TestWeaveMerge(TestCaseWithTransport, TestMergeImplementation):
 
1151
 
 
1152
    merge_type = _mod_merge.WeaveMerger
 
1153
 
 
1154
 
 
1155
class TestLCAMerge(TestCaseWithTransport, TestMergeImplementation):
 
1156
 
 
1157
    merge_type = _mod_merge.LCAMerger
 
1158
 
 
1159
    def test_merge_move_and_change(self):
 
1160
        self.expectFailure("lca merge doesn't conflict for move and change",
 
1161
            super(TestLCAMerge, self).test_merge_move_and_change)
 
1162
 
 
1163
 
1141
1164
class LoggingMerger(object):
1142
1165
    # These seem to be the required attributes
1143
1166
    requires_base = False
1198
1221
        mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1199
1222
        mem_tree.lock_write()
1200
1223
        self.addCleanup(mem_tree.unlock)
1201
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
1224
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
1202
1225
            mem_tree, other_revision_id)
1203
1226
        merger.set_interesting_files(interesting_files)
1204
1227
        # It seems there is no matching function for set_interesting_ids
1209
1232
 
1210
1233
class TestMergerInMemory(TestMergerBase):
1211
1234
 
1212
 
    def test_cache_trees_with_revision_ids_None(self):
1213
 
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1214
 
        original_cache = dict(merger._cached_trees)
1215
 
        merger.cache_trees_with_revision_ids([None])
1216
 
        self.assertEqual(original_cache, merger._cached_trees)
1217
 
 
1218
 
    def test_cache_trees_with_revision_ids_no_revision_id(self):
1219
 
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1220
 
        original_cache = dict(merger._cached_trees)
1221
 
        tree = self.make_branch_and_memory_tree('tree')
1222
 
        merger.cache_trees_with_revision_ids([tree])
1223
 
        self.assertEqual(original_cache, merger._cached_trees)
1224
 
 
1225
 
    def test_cache_trees_with_revision_ids_having_revision_id(self):
1226
 
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1227
 
        original_cache = dict(merger._cached_trees)
1228
 
        tree = merger.this_branch.repository.revision_tree('B-id')
1229
 
        original_cache['B-id'] = tree
1230
 
        merger.cache_trees_with_revision_ids([tree])
1231
 
        self.assertEqual(original_cache, merger._cached_trees)
1232
 
 
1233
1235
    def test_find_base(self):
1234
1236
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1235
1237
        self.assertEqual('A-id', merger.base_rev_id)
1978
1980
 
1979
1981
    def do_merge(self, builder, other_revision_id):
1980
1982
        wt = self.get_wt_from_builder(builder)
1981
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
1983
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
1982
1984
            wt, other_revision_id)
1983
1985
        merger.merge_type = _mod_merge.Merge3Merger
1984
1986
        return wt, merger.do_merge()
2244
2246
        wt.commit('D merges B & C', rev_id='D-id')
2245
2247
        self.assertEqual('barry', wt.id2path('foo-id'))
2246
2248
        # Check the output of the Merger object directly
2247
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2249
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2248
2250
            wt, 'F-id')
2249
2251
        merger.merge_type = _mod_merge.Merge3Merger
2250
2252
        merge_obj = merger.make_merger()
2300
2302
        wt.commit('F foo => bing', rev_id='F-id')
2301
2303
 
2302
2304
        # Check the output of the Merger object directly
2303
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2305
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2304
2306
            wt, 'E-id')
2305
2307
        merger.merge_type = _mod_merge.Merge3Merger
2306
2308
        merge_obj = merger.make_merger()
2351
2353
        list(wt.iter_changes(wt.basis_tree()))
2352
2354
        wt.commit('D merges B & C, makes it a file', rev_id='D-id')
2353
2355
 
2354
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2356
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2355
2357
            wt, 'E-id')
2356
2358
        merger.merge_type = _mod_merge.Merge3Merger
2357
2359
        merge_obj = merger.make_merger()
2566
2568
        wt.branch.set_last_revision_info(2, 'B-id')
2567
2569
        wt.commit('D', rev_id='D-id', recursive=None)
2568
2570
 
2569
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2571
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2570
2572
            wt, 'E-id')
2571
2573
        merger.merge_type = _mod_merge.Merge3Merger
2572
2574
        merge_obj = merger.make_merger()
2603
2605
        wt.branch.set_last_revision_info(2, 'B-id')
2604
2606
        wt.commit('D', rev_id='D-id', recursive=None)
2605
2607
 
2606
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2608
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2607
2609
            wt, 'E-id')
2608
2610
        merger.merge_type = _mod_merge.Merge3Merger
2609
2611
        merge_obj = merger.make_merger()
2643
2645
        wt.branch.set_last_revision_info(2, 'B-id')
2644
2646
        wt.commit('D', rev_id='D-id', recursive=None)
2645
2647
 
2646
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2648
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2647
2649
            wt, 'E-id')
2648
2650
        merger.merge_type = _mod_merge.Merge3Merger
2649
2651
        merge_obj = merger.make_merger()
2688
2690
        wt.branch.set_last_revision_info(2, 'B-id')
2689
2691
        wt.commit('D', rev_id='D-id', recursive=None)
2690
2692
 
2691
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2693
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2692
2694
            wt, 'E-id')
2693
2695
        merger.merge_type = _mod_merge.Merge3Merger
2694
2696
        merge_obj = merger.make_merger()
2830
2832
            'bval', ['lca1val', 'lca2val', 'lca2val'], 'oval', 'tval')
2831
2833
        self.assertLCAMultiWay('conflict',
2832
2834
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'oval', 'tval')
2833
 
 
2834
 
 
2835
 
class TestConfigurableFileMerger(tests.TestCaseWithTransport):
2836
 
 
2837
 
    def setUp(self):
2838
 
        super(TestConfigurableFileMerger, self).setUp()
2839
 
        self.calls = []
2840
 
 
2841
 
    def get_merger_factory(self):
2842
 
        # Allows  the inner methods to access the test attributes
2843
 
        test = self
2844
 
 
2845
 
        class FooMerger(_mod_merge.ConfigurableFileMerger):
2846
 
            name_prefix = "foo"
2847
 
            default_files = ['bar']
2848
 
 
2849
 
            def merge_text(self, params):
2850
 
                test.calls.append('merge_text')
2851
 
                return ('not_applicable', None)
2852
 
 
2853
 
        def factory(merger):
2854
 
            result = FooMerger(merger)
2855
 
            # Make sure we start with a clean slate
2856
 
            self.assertEqual(None, result.affected_files)
2857
 
            # Track the original merger
2858
 
            self.merger = result
2859
 
            return result
2860
 
 
2861
 
        return factory
2862
 
 
2863
 
    def _install_hook(self, factory):
2864
 
        _mod_merge.Merger.hooks.install_named_hook('merge_file_content',
2865
 
                                                   factory, 'test factory')
2866
 
 
2867
 
    def make_builder(self):
2868
 
        builder = test_merge_core.MergeBuilder(self.test_base_dir)
2869
 
        self.addCleanup(builder.cleanup)
2870
 
        return builder
2871
 
 
2872
 
    def make_text_conflict(self, file_name='bar'):
2873
 
        factory = self.get_merger_factory()
2874
 
        self._install_hook(factory)
2875
 
        builder = self.make_builder()
2876
 
        builder.add_file('bar-id', builder.tree_root, file_name, 'text1', True)
2877
 
        builder.change_contents('bar-id', other='text4', this='text3')
2878
 
        return builder
2879
 
 
2880
 
    def make_kind_change(self):
2881
 
        factory = self.get_merger_factory()
2882
 
        self._install_hook(factory)
2883
 
        builder = self.make_builder()
2884
 
        builder.add_file('bar-id', builder.tree_root, 'bar', 'text1', True,
2885
 
                         this=False)
2886
 
        builder.add_dir('bar-dir', builder.tree_root, 'bar-id',
2887
 
                        base=False, other=False)
2888
 
        return builder
2889
 
 
2890
 
    def test_uses_this_branch(self):
2891
 
        builder = self.make_text_conflict()
2892
 
        tt = builder.make_preview_transform()
2893
 
        self.addCleanup(tt.finalize)
2894
 
 
2895
 
    def test_affected_files_cached(self):
2896
 
        """Ensures that the config variable is cached"""
2897
 
        builder = self.make_text_conflict()
2898
 
        conflicts = builder.merge()
2899
 
        # The hook should set the variable
2900
 
        self.assertEqual(['bar'], self.merger.affected_files)
2901
 
        self.assertEqual(1, len(conflicts))
2902
 
 
2903
 
    def test_hook_called_for_text_conflicts(self):
2904
 
        builder = self.make_text_conflict()
2905
 
        conflicts = builder.merge()
2906
 
        # The hook should call the merge_text() method
2907
 
        self.assertEqual(['merge_text'], self.calls)
2908
 
 
2909
 
    def test_hook_not_called_for_kind_change(self):
2910
 
        builder = self.make_kind_change()
2911
 
        conflicts = builder.merge()
2912
 
        # The hook should not call the merge_text() method
2913
 
        self.assertEqual([], self.calls)
2914
 
 
2915
 
    def test_hook_not_called_for_other_files(self):
2916
 
        builder = self.make_text_conflict('foobar')
2917
 
        conflicts = builder.merge()
2918
 
        # The hook should not call the merge_text() method
2919
 
        self.assertEqual([], self.calls)