/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-07-31 17:42:29 UTC
  • mto: This revision was merged to the branch mainline in revision 4611.
  • Revision ID: john@arbash-meinel.com-20090731174229-w2zdsdlfpeddk8gl
Now we got to the per-workingtree tests, etc.

The main causes seem to break down into:
  bzrdir.clone() is known to be broken wrt locking, this effects
  everything that tries to 'push'

  shelf code is not compatible with strict locking

  merge code seems to have an issue. This might actually be the
  root cause of the clone() problems.

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
 
120
117
 
121
118
    def test_create_rename(self):
122
119
        """Rename an inventory entry while creating the file"""
 
120
        self.thisFailsStrictLockCheck()
123
121
        tree =self.make_branch_and_tree('.')
124
122
        file('name1', 'wb').write('Hello')
125
123
        tree.add('name1')
130
128
 
131
129
    def test_layered_rename(self):
132
130
        """Rename both child and parent at same time"""
 
131
        self.thisFailsStrictLockCheck()
133
132
        tree =self.make_branch_and_tree('.')
134
133
        os.mkdir('dirname1')
135
134
        tree.add('dirname1')
154
153
        log = StringIO()
155
154
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
156
155
                    this_tree=tree_b, ignore_zero=True)
157
 
        self.failUnless('All changes applied successfully.\n' not in
158
 
            self.get_log())
 
156
        log = self._get_log(keep_log_file=True)
 
157
        self.failUnless('All changes applied successfully.\n' not in log)
159
158
        tree_b.revert()
160
159
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
161
160
                    this_tree=tree_b, ignore_zero=False)
162
 
        self.failUnless('All changes applied successfully.\n' in self.get_log())
 
161
        log = self._get_log(keep_log_file=True)
 
162
        self.failUnless('All changes applied successfully.\n' in log)
163
163
 
164
164
    def test_merge_inner_conflicts(self):
165
165
        tree_a = self.make_branch_and_tree('a')
215
215
        self.assertFileEqual('text2', 'tree/sub-tree/file')
216
216
 
217
217
    def test_merge_with_missing(self):
 
218
        self.thisFailsStrictLockCheck()
218
219
        tree_a = self.make_branch_and_tree('tree_a')
219
220
        self.build_tree_contents([('tree_a/file', 'content_1')])
220
221
        tree_a.add('file')
221
222
        tree_a.commit('commit base')
222
223
        # 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.
 
224
        # the basis tree. This mutates the tree after grabbing basis, so go to
 
225
        # the repository.
225
226
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
226
227
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
227
228
        self.build_tree_contents([('tree_a/file', 'content_2')])
228
229
        tree_a.commit('commit other')
229
230
        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
231
        os.unlink('tree_b/file')
233
232
        merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b)
234
233
 
295
294
        tree_a.commit('commit 2')
296
295
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
297
296
        tree_b.rename_one('file_1', 'renamed')
298
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
 
297
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
 
298
                                                    progress.DummyProgress())
299
299
        merger.merge_type = _mod_merge.Merge3Merger
300
300
        merger.do_merge()
301
301
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
309
309
        tree_a.commit('commit 2')
310
310
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
311
311
        tree_b.rename_one('file_1', 'renamed')
312
 
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
 
312
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
 
313
                                                    progress.DummyProgress())
313
314
        merger.merge_type = _mod_merge.WeaveMerger
314
315
        merger.do_merge()
315
316
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
316
317
 
 
318
    def test_Merger_defaults_to_DummyProgress(self):
 
319
        branch = self.make_branch('branch')
 
320
        merger = _mod_merge.Merger(branch, pb=None)
 
321
        self.assertIsInstance(merger._pb, progress.DummyProgress)
 
322
 
317
323
    def prepare_cherrypick(self):
318
324
        """Prepare a pair of trees for cherrypicking tests.
319
325
 
340
346
 
341
347
    def test_weave_cherrypick(self):
342
348
        this_tree, other_tree = self.prepare_cherrypick()
343
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
349
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
344
350
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
345
351
        merger.merge_type = _mod_merge.WeaveMerger
346
352
        merger.do_merge()
348
354
 
349
355
    def test_weave_cannot_reverse_cherrypick(self):
350
356
        this_tree, other_tree = self.prepare_cherrypick()
351
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
357
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
352
358
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
353
359
        merger.merge_type = _mod_merge.WeaveMerger
354
360
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
355
361
 
356
362
    def test_merge3_can_reverse_cherrypick(self):
357
363
        this_tree, other_tree = self.prepare_cherrypick()
358
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
364
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
359
365
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
360
366
        merger.merge_type = _mod_merge.Merge3Merger
361
367
        merger.do_merge()
373
379
        this_tree.lock_write()
374
380
        self.addCleanup(this_tree.unlock)
375
381
 
376
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
382
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
377
383
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
378
384
        merger.merge_type = _mod_merge.Merge3Merger
379
385
        merger.do_merge()
392
398
        other_tree.commit('rev2', rev_id='rev2b')
393
399
        this_tree.lock_write()
394
400
        self.addCleanup(this_tree.unlock)
395
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
401
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress,
396
402
            this_tree, 'rev2b', other_branch=other_tree.branch)
397
403
        merger.merge_type = _mod_merge.Merge3Merger
398
404
        tree_merger = merger.make_merger()
412
418
        other_tree.commit('rev2', rev_id='rev2b')
413
419
        this_tree.lock_write()
414
420
        self.addCleanup(this_tree.unlock)
415
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
421
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
416
422
            this_tree, 'rev2b', other_branch=other_tree.branch)
417
423
        merger.merge_type = _mod_merge.Merge3Merger
418
424
        tree_merger = merger.make_merger()
442
448
        other_tree.commit('rev2', rev_id='rev2b')
443
449
        this_tree.lock_write()
444
450
        self.addCleanup(this_tree.unlock)
445
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
451
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
446
452
            this_tree, 'rev2b', other_branch=other_tree.branch)
447
453
        merger.merge_type = _mod_merge.Merge3Merger
448
454
        tree_merger = merger.make_merger()
519
525
        self.add_uncommitted_version(('root', 'C:'), [('root', 'A')], 'fabg')
520
526
        return _PlanMerge('B:', 'C:', self.plan_merge_vf, ('root',))
521
527
 
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
528
    def test_unique_lines(self):
529
529
        plan = self.setup_plan_merge()
530
530
        self.assertEqual(plan._unique_lines(
828
828
                          ('unchanged', 'f\n'),
829
829
                          ('unchanged', 'g\n')],
830
830
                         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
831
 
937
832
    def assertRemoveExternalReferences(self, filtered_parent_map,
938
833
                                       child_map, tails, parent_map):
1138
1033
                         ], list(plan))
1139
1034
 
1140
1035
 
 
1036
class TestMergeImplementation(object):
 
1037
 
 
1038
    def do_merge(self, target_tree, source_tree, **kwargs):
 
1039
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
 
1040
            target_tree, source_tree.last_revision(),
 
1041
            other_branch=source_tree.branch)
 
1042
        merger.merge_type=self.merge_type
 
1043
        for name, value in kwargs.items():
 
1044
            setattr(merger, name, value)
 
1045
        merger.do_merge()
 
1046
 
 
1047
    def test_merge_specific_file(self):
 
1048
        this_tree = self.make_branch_and_tree('this')
 
1049
        this_tree.lock_write()
 
1050
        self.addCleanup(this_tree.unlock)
 
1051
        self.build_tree_contents([
 
1052
            ('this/file1', 'a\nb\n'),
 
1053
            ('this/file2', 'a\nb\n')
 
1054
        ])
 
1055
        this_tree.add(['file1', 'file2'])
 
1056
        this_tree.commit('Added files')
 
1057
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
1058
        self.build_tree_contents([
 
1059
            ('other/file1', 'a\nb\nc\n'),
 
1060
            ('other/file2', 'a\nb\nc\n')
 
1061
        ])
 
1062
        other_tree.commit('modified both')
 
1063
        self.build_tree_contents([
 
1064
            ('this/file1', 'd\na\nb\n'),
 
1065
            ('this/file2', 'd\na\nb\n')
 
1066
        ])
 
1067
        this_tree.commit('modified both')
 
1068
        self.do_merge(this_tree, other_tree, interesting_files=['file1'])
 
1069
        self.assertFileEqual('d\na\nb\nc\n', 'this/file1')
 
1070
        self.assertFileEqual('d\na\nb\n', 'this/file2')
 
1071
 
 
1072
    def test_merge_move_and_change(self):
 
1073
        this_tree = self.make_branch_and_tree('this')
 
1074
        this_tree.lock_write()
 
1075
        self.addCleanup(this_tree.unlock)
 
1076
        self.build_tree_contents([
 
1077
            ('this/file1', 'line 1\nline 2\nline 3\nline 4\n'),
 
1078
        ])
 
1079
        this_tree.add('file1',)
 
1080
        this_tree.commit('Added file')
 
1081
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
 
1082
        self.build_tree_contents([
 
1083
            ('other/file1', 'line 1\nline 2 to 2.1\nline 3\nline 4\n'),
 
1084
        ])
 
1085
        other_tree.commit('Changed 2 to 2.1')
 
1086
        self.build_tree_contents([
 
1087
            ('this/file1', 'line 1\nline 3\nline 2\nline 4\n'),
 
1088
        ])
 
1089
        this_tree.commit('Swapped 2 & 3')
 
1090
        self.do_merge(this_tree, other_tree)
 
1091
        self.assertFileEqual('line 1\n'
 
1092
            '<<<<<<< TREE\n'
 
1093
            'line 3\n'
 
1094
            'line 2\n'
 
1095
            '=======\n'
 
1096
            'line 2 to 2.1\n'
 
1097
            'line 3\n'
 
1098
            '>>>>>>> MERGE-SOURCE\n'
 
1099
            'line 4\n', 'this/file1')
 
1100
 
 
1101
    def test_modify_conflicts_with_delete(self):
 
1102
        # If one side deletes a line, and the other modifies that line, then
 
1103
        # the modification should be considered a conflict
 
1104
        builder = self.make_branch_builder('test')
 
1105
        builder.start_series()
 
1106
        builder.build_snapshot('BASE-id', None,
 
1107
            [('add', ('', None, 'directory', None)),
 
1108
             ('add', ('foo', 'foo-id', 'file', 'a\nb\nc\nd\ne\n')),
 
1109
            ])
 
1110
        # Delete 'b\n'
 
1111
        builder.build_snapshot('OTHER-id', ['BASE-id'],
 
1112
            [('modify', ('foo-id', 'a\nc\nd\ne\n'))])
 
1113
        # Modify 'b\n', add 'X\n'
 
1114
        builder.build_snapshot('THIS-id', ['BASE-id'],
 
1115
            [('modify', ('foo-id', 'a\nb2\nc\nd\nX\ne\n'))])
 
1116
        builder.finish_series()
 
1117
        branch = builder.get_branch()
 
1118
        this_tree = branch.bzrdir.create_workingtree()
 
1119
        this_tree.lock_write()
 
1120
        self.addCleanup(this_tree.unlock)
 
1121
        other_tree = this_tree.bzrdir.sprout('other', 'OTHER-id').open_workingtree()
 
1122
        self.do_merge(this_tree, other_tree)
 
1123
        if self.merge_type is _mod_merge.LCAMerger:
 
1124
            self.expectFailure("lca merge doesn't track deleted lines",
 
1125
                self.assertFileEqual,
 
1126
                    'a\n'
 
1127
                    '<<<<<<< TREE\n'
 
1128
                    'b2\n'
 
1129
                    '=======\n'
 
1130
                    '>>>>>>> MERGE-SOURCE\n'
 
1131
                    'c\n'
 
1132
                    'd\n'
 
1133
                    'X\n'
 
1134
                    'e\n', 'test/foo')
 
1135
        else:
 
1136
            self.assertFileEqual(
 
1137
                'a\n'
 
1138
                '<<<<<<< TREE\n'
 
1139
                'b2\n'
 
1140
                '=======\n'
 
1141
                '>>>>>>> MERGE-SOURCE\n'
 
1142
                'c\n'
 
1143
                'd\n'
 
1144
                'X\n'
 
1145
                'e\n', 'test/foo')
 
1146
 
 
1147
 
 
1148
class TestMerge3Merge(TestCaseWithTransport, TestMergeImplementation):
 
1149
 
 
1150
    merge_type = _mod_merge.Merge3Merger
 
1151
 
 
1152
 
 
1153
class TestWeaveMerge(TestCaseWithTransport, TestMergeImplementation):
 
1154
 
 
1155
    merge_type = _mod_merge.WeaveMerger
 
1156
 
 
1157
 
 
1158
class TestLCAMerge(TestCaseWithTransport, TestMergeImplementation):
 
1159
 
 
1160
    merge_type = _mod_merge.LCAMerger
 
1161
 
 
1162
    def test_merge_move_and_change(self):
 
1163
        self.expectFailure("lca merge doesn't conflict for move and change",
 
1164
            super(TestLCAMerge, self).test_merge_move_and_change)
 
1165
 
 
1166
 
1141
1167
class LoggingMerger(object):
1142
1168
    # These seem to be the required attributes
1143
1169
    requires_base = False
1198
1224
        mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1199
1225
        mem_tree.lock_write()
1200
1226
        self.addCleanup(mem_tree.unlock)
1201
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
1227
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
1202
1228
            mem_tree, other_revision_id)
1203
1229
        merger.set_interesting_files(interesting_files)
1204
1230
        # It seems there is no matching function for set_interesting_ids
1209
1235
 
1210
1236
class TestMergerInMemory(TestMergerBase):
1211
1237
 
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
1238
    def test_find_base(self):
1234
1239
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1235
1240
        self.assertEqual('A-id', merger.base_rev_id)
1978
1983
 
1979
1984
    def do_merge(self, builder, other_revision_id):
1980
1985
        wt = self.get_wt_from_builder(builder)
1981
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
1986
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
1982
1987
            wt, other_revision_id)
1983
1988
        merger.merge_type = _mod_merge.Merge3Merger
1984
1989
        return wt, merger.do_merge()
2244
2249
        wt.commit('D merges B & C', rev_id='D-id')
2245
2250
        self.assertEqual('barry', wt.id2path('foo-id'))
2246
2251
        # Check the output of the Merger object directly
2247
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2252
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2248
2253
            wt, 'F-id')
2249
2254
        merger.merge_type = _mod_merge.Merge3Merger
2250
2255
        merge_obj = merger.make_merger()
2300
2305
        wt.commit('F foo => bing', rev_id='F-id')
2301
2306
 
2302
2307
        # Check the output of the Merger object directly
2303
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2308
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2304
2309
            wt, 'E-id')
2305
2310
        merger.merge_type = _mod_merge.Merge3Merger
2306
2311
        merge_obj = merger.make_merger()
2351
2356
        list(wt.iter_changes(wt.basis_tree()))
2352
2357
        wt.commit('D merges B & C, makes it a file', rev_id='D-id')
2353
2358
 
2354
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2359
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2355
2360
            wt, 'E-id')
2356
2361
        merger.merge_type = _mod_merge.Merge3Merger
2357
2362
        merge_obj = merger.make_merger()
2566
2571
        wt.branch.set_last_revision_info(2, 'B-id')
2567
2572
        wt.commit('D', rev_id='D-id', recursive=None)
2568
2573
 
2569
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2574
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2570
2575
            wt, 'E-id')
2571
2576
        merger.merge_type = _mod_merge.Merge3Merger
2572
2577
        merge_obj = merger.make_merger()
2603
2608
        wt.branch.set_last_revision_info(2, 'B-id')
2604
2609
        wt.commit('D', rev_id='D-id', recursive=None)
2605
2610
 
2606
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2611
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2607
2612
            wt, 'E-id')
2608
2613
        merger.merge_type = _mod_merge.Merge3Merger
2609
2614
        merge_obj = merger.make_merger()
2643
2648
        wt.branch.set_last_revision_info(2, 'B-id')
2644
2649
        wt.commit('D', rev_id='D-id', recursive=None)
2645
2650
 
2646
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2651
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2647
2652
            wt, 'E-id')
2648
2653
        merger.merge_type = _mod_merge.Merge3Merger
2649
2654
        merge_obj = merger.make_merger()
2688
2693
        wt.branch.set_last_revision_info(2, 'B-id')
2689
2694
        wt.commit('D', rev_id='D-id', recursive=None)
2690
2695
 
2691
 
        merger = _mod_merge.Merger.from_revision_ids(None,
 
2696
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
2692
2697
            wt, 'E-id')
2693
2698
        merger.merge_type = _mod_merge.Merge3Merger
2694
2699
        merge_obj = merger.make_merger()
2830
2835
            'bval', ['lca1val', 'lca2val', 'lca2val'], 'oval', 'tval')
2831
2836
        self.assertLCAMultiWay('conflict',
2832
2837
            '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)