/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2255.2.217 by Martin Pool
docs
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
17
import os
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
18
from StringIO import StringIO
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
19
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
20
from bzrlib import (
21
    conflicts,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
22
    errors,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
23
    knit,
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
24
    memorytree,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
25
    merge as _mod_merge,
26
    option,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
27
    progress,
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
28
    transform,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
29
    versionedfile,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
30
    )
974.1.56 by aaron.bentley at utoronto
Added merge test
31
from bzrlib.branch import Branch
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
32
from bzrlib.conflicts import ConflictList, TextConflict
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
33
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
34
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
35
from bzrlib.osutils import pathjoin, file_kind
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
36
from bzrlib.tests import TestCaseWithTransport, TestCaseWithMemoryTransport
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
37
from bzrlib.trace import (enable_test_log, disable_test_log)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
38
from bzrlib.workingtree import WorkingTree
39
40
41
class TestMerge(TestCaseWithTransport):
974.1.56 by aaron.bentley at utoronto
Added merge test
42
    """Test appending more than one revision"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
43
974.1.56 by aaron.bentley at utoronto
Added merge test
44
    def test_pending(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
45
        wt = self.make_branch_and_tree('.')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
46
        rev_a = wt.commit("lala!")
47
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
48
        self.assertRaises(errors.PointlessMerge, wt.merge_from_branch,
49
                          wt.branch)
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
50
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
51
        return wt
974.1.80 by Aaron Bentley
Improved merge error handling and testing
52
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
53
    def test_undo(self):
54
        wt = self.make_branch_and_tree('.')
55
        wt.commit("lala!")
56
        wt.commit("haha!")
57
        wt.commit("blabla!")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
58
        wt.merge_from_branch(wt.branch, wt.branch.get_rev_id(2),
59
                             wt.branch.get_rev_id(1))
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
60
974.1.80 by Aaron Bentley
Improved merge error handling and testing
61
    def test_nocommits(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
62
        wt = self.test_pending()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
63
        wt2 = self.make_branch_and_tree('branch2')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
64
        self.assertRaises(NoCommits, wt.merge_from_branch, wt2.branch)
65
        return wt, wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
66
67
    def test_unrelated(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
68
        wt, wt2 = self.test_nocommits()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
69
        wt2.commit("blah")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
70
        self.assertRaises(UnrelatedBranches, wt.merge_from_branch, wt2.branch)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
71
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
72
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
73
    def test_merge_one_file(self):
74
        """Do a partial merge of a tree which should not affect tree parents."""
1645.1.1 by Aaron Bentley
Implement single-file merge
75
        wt1 = self.make_branch_and_tree('branch1')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
76
        tip = wt1.commit('empty commit')
1645.1.1 by Aaron Bentley
Implement single-file merge
77
        wt2 = self.make_branch_and_tree('branch2')
78
        wt2.pull(wt1.branch)
79
        file('branch1/foo', 'wb').write('foo')
80
        file('branch1/bar', 'wb').write('bar')
81
        wt1.add('foo')
82
        wt1.add('bar')
83
        wt1.commit('add foobar')
84
        os.chdir('branch2')
2530.3.1 by Martin Pool
Cleanup old variations on run_bzr in the test suite
85
        self.run_bzr('merge ../branch1/baz', retcode=3)
86
        self.run_bzr('merge ../branch1/foo')
1645.1.1 by Aaron Bentley
Implement single-file merge
87
        self.failUnlessExists('foo')
88
        self.failIfExists('bar')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
89
        wt2 = WorkingTree.open('.') # opens branch2
90
        self.assertEqual([tip], wt2.get_parent_ids())
1908.6.9 by Robert Collins
Fix status to not use pending_merges.
91
        
974.1.88 by Aaron Bentley
Set a pending_merge if the merge base is forced to revno 0
92
    def test_pending_with_null(self):
1551.8.25 by Aaron Bentley
Fix deprecated use of pending_merges
93
        """When base is forced to revno 0, parent_ids are set"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
94
        wt2 = self.test_unrelated()
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
95
        wt1 = WorkingTree.open('.')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
96
        br1 = wt1.branch
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
97
        br1.fetch(wt2.branch)
1390 by Robert Collins
pair programming worx... merge integration and weave
98
        # merge all of branch 2 into branch 1 even though they 
99
        # are not related.
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
100
        wt1.merge_from_branch(wt2.branch, wt2.last_revision(), 'null:')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
101
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
102
            wt1.get_parent_ids())
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
103
        return (wt1, wt2.branch)
974.1.89 by Aaron Bentley
Fixed merging with multiple roots, by using null as graph root.
104
105
    def test_two_roots(self):
106
        """Merge base is sane when two unrelated branches are merged"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
107
        wt1, br2 = self.test_pending_with_null()
108
        wt1.commit("blah")
3228.4.15 by John Arbash Meinel
Stop using common_ancestor
109
        wt1.lock_read()
110
        try:
111
            last = wt1.branch.last_revision()
112
            last2 = br2.last_revision()
113
            graph = wt1.branch.repository.get_graph()
114
            self.assertEqual(last2, graph.find_unique_lca(last, last2))
115
        finally:
116
            wt1.unlock()
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
117
118
    def test_create_rename(self):
119
        """Rename an inventory entry while creating the file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
120
        tree =self.make_branch_and_tree('.')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
121
        file('name1', 'wb').write('Hello')
122
        tree.add('name1')
123
        tree.commit(message="hello")
124
        tree.rename_one('name1', 'name2')
125
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
126
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
127
128
    def test_layered_rename(self):
129
        """Rename both child and parent at same time"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
130
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
131
        os.mkdir('dirname1')
132
        tree.add('dirname1')
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
133
        filename = pathjoin('dirname1', 'name1')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
134
        file(filename, 'wb').write('Hello')
135
        tree.add(filename)
136
        tree.commit(message="hello")
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
137
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
138
        tree.rename_one(filename, filename2)
139
        tree.rename_one('dirname1', 'dirname2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
140
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
141
142
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
143
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
144
        tree_a =self.make_branch_and_tree('a')
145
        tree_a.commit(message="hello")
146
        dir_b = tree_a.bzrdir.sprout('b')
147
        tree_b = dir_b.open_workingtree()
3146.4.4 by Aaron Bentley
Add write lock, so merge_inner works properly
148
        tree_b.lock_write()
149
        self.addCleanup(tree_b.unlock)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
150
        tree_a.commit(message="hello again")
151
        log = StringIO()
152
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
153
                    this_tree=tree_b, ignore_zero=True)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
154
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
155
        self.failUnless('All changes applied successfully.\n' not in log)
2796.1.3 by Aaron Bentley
update new test case
156
        tree_b.revert()
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
157
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
158
                    this_tree=tree_b, ignore_zero=False)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
159
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
160
        self.failUnless('All changes applied successfully.\n' in log)
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
161
162
    def test_merge_inner_conflicts(self):
163
        tree_a = self.make_branch_and_tree('a')
164
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
165
        merge_inner(tree_a.branch, tree_a, tree_a, this_tree=tree_a)
1551.7.13 by Aaron Bentley
Switched from actual, expected to expected, actual, for John.
166
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
167
168
    def test_rmdir_conflict(self):
169
        tree_a = self.make_branch_and_tree('a')
170
        self.build_tree(['a/b/'])
171
        tree_a.add('b', 'b-id')
172
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
173
        # basis_tree() is only guaranteed to be valid as long as it is actually
174
        # the basis tree. This mutates the tree after grabbing basis, so go to
175
        # the repository.
176
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
177
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
178
        self.build_tree(['a/b/c'])
179
        tree_a.add('b/c')
180
        tree_a.commit('added c')
181
        os.rmdir('z/b')
182
        tree_z.commit('removed b')
183
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
184
        self.assertEqual([
185
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
186
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
187
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
188
        merge_inner(tree_a.branch, tree_z.basis_tree(), base_tree,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
189
                    this_tree=tree_a)
190
        self.assertEqual([
191
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
192
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
193
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
194
2100.3.29 by Aaron Bentley
Get merge working initially
195
    def test_nested_merge(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
196
        tree = self.make_branch_and_tree('tree',
197
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
198
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
199
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
200
        sub_tree.set_root_id('sub-tree-root')
201
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
202
        sub_tree.add('file')
203
        sub_tree.commit('foo')
204
        tree.add_reference(sub_tree)
205
        tree.commit('set text to 1')
206
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
207
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
208
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
209
        # and merge the changes from the diverged subtree into the containing
210
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
211
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
212
        tree.merge_from_branch(tree2.branch)
213
        self.assertFileEqual('text2', 'tree/sub-tree/file')
214
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
215
    def test_merge_with_missing(self):
216
        tree_a = self.make_branch_and_tree('tree_a')
217
        self.build_tree_contents([('tree_a/file', 'content_1')])
218
        tree_a.add('file')
219
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
220
        # basis_tree() is only guaranteed to be valid as long as it is actually
221
        # the basis tree. This mutates the tree after grabbing basis, so go to
222
        # the repository.
223
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
224
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
225
        self.build_tree_contents([('tree_a/file', 'content_2')])
226
        tree_a.commit('commit other')
227
        other_tree = tree_a.basis_tree()
228
        os.unlink('tree_b/file')
229
        merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b)
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
230
231
    def test_merge_kind_change(self):
232
        tree_a = self.make_branch_and_tree('tree_a')
233
        self.build_tree_contents([('tree_a/file', 'content_1')])
234
        tree_a.add('file', 'file-id')
235
        tree_a.commit('added file')
236
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
237
        os.unlink('tree_a/file')
238
        self.build_tree(['tree_a/file/'])
239
        tree_a.commit('changed file to directory')
240
        tree_b.merge_from_branch(tree_a.branch)
241
        self.assertEqual('directory', file_kind('tree_b/file'))
2748.3.2 by Aaron Bentley
Fix revert, remove-tree, and various tests to use None for 'no files specified'
242
        tree_b.revert()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
243
        self.assertEqual('file', file_kind('tree_b/file'))
244
        self.build_tree_contents([('tree_b/file', 'content_2')])
245
        tree_b.commit('content change')
246
        tree_b.merge_from_branch(tree_a.branch)
247
        self.assertEqual(tree_b.conflicts(),
248
                         [conflicts.ContentsConflict('file',
249
                          file_id='file-id')])
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
250
    
251
    def test_merge_type_registry(self):
252
        merge_type_option = option.Option.OPTIONS['merge-type']
253
        self.assertFalse('merge4' in [x[0] for x in 
254
                        merge_type_option.iter_switches()])
255
        registry = _mod_merge.get_merge_type_registry()
256
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
257
                               'time-travelling merge')
258
        self.assertTrue('merge4' in [x[0] for x in 
259
                        merge_type_option.iter_switches()])
260
        registry.remove('merge4')
261
        self.assertFalse('merge4' in [x[0] for x in 
262
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
263
1551.16.3 by Aaron Bentley
Rename test case
264
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
265
        tree_a = self.make_branch_and_tree('A')
266
        tree_a.lock_write()
267
        self.addCleanup(tree_a.unlock)
268
        self.build_tree(['A/a'])
269
        tree_a.add('a')
270
        tree_a.commit('1', rev_id='rev-1')
271
        tree_a.flush()
272
        tree_a.rename_one('a', 'b')
273
        tree_a.commit('2')
274
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
275
        tree_b = bzrdir_b.open_workingtree()
276
        tree_b.lock_write()
277
        self.addCleanup(tree_b.unlock)
278
        os.unlink('B/a')
279
        tree_b.commit('3')
280
        try:
281
            tree_b.merge_from_branch(tree_a.branch)
282
        except AttributeError:
283
            self.fail('tried to join a path when name was None')
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
284
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
285
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis(self):
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
286
        tree_a = self.make_branch_and_tree('a')
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
287
        self.build_tree(['a/file_1', 'a/file_2'])
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
288
        tree_a.add(['file_1'])
289
        tree_a.commit('commit 1')
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
290
        tree_a.add(['file_2'])
291
        tree_a.commit('commit 2')
2644.1.1 by Wouter van Heyst
Fix bug #127115 by checking for self.other_rev_id being None in Merger.set_pending()
292
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
293
        tree_b.rename_one('file_1', 'renamed')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
294
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
295
                                                    progress.DummyProgress())
296
        merger.merge_type = _mod_merge.Merge3Merger
297
        merger.do_merge()
2644.1.2 by Wouter van Heyst
As Aaron explained #127115 is more general, failing whenever other's basis is an ancestor of this' basis.
298
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
299
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
300
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis_weave(self):
301
        tree_a = self.make_branch_and_tree('a')
302
        self.build_tree(['a/file_1', 'a/file_2'])
303
        tree_a.add(['file_1'])
304
        tree_a.commit('commit 1')
305
        tree_a.add(['file_2'])
306
        tree_a.commit('commit 2')
307
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
308
        tree_b.rename_one('file_1', 'renamed')
309
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
310
                                                    progress.DummyProgress())
311
        merger.merge_type = _mod_merge.WeaveMerger
312
        merger.do_merge()
313
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
314
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
315
    def prepare_cherrypick(self):
3062.2.13 by Aaron Bentley
Update prepare_cherrypick docstring
316
        """Prepare a pair of trees for cherrypicking tests.
317
318
        Both trees have a file, 'file'.
319
        rev1 sets content to 'a'.
320
        rev2b adds 'b'.
321
        rev3b adds 'c'.
322
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
323
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
324
        'c', but not 'b'.
325
        """
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
326
        this_tree = self.make_branch_and_tree('this')
327
        self.build_tree_contents([('this/file', "a\n")])
328
        this_tree.add('file')
329
        this_tree.commit('rev1')
330
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
331
        self.build_tree_contents([('other/file', "a\nb\n")])
332
        other_tree.commit('rev2b', rev_id='rev2b')
333
        self.build_tree_contents([('other/file', "c\na\nb\n")])
334
        other_tree.commit('rev3b', rev_id='rev3b')
335
        this_tree.lock_write()
336
        self.addCleanup(this_tree.unlock)
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
337
        return this_tree, other_tree
338
339
    def test_weave_cherrypick(self):
340
        this_tree, other_tree = self.prepare_cherrypick()
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
341
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
342
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
343
        merger.merge_type = _mod_merge.WeaveMerger
344
        merger.do_merge()
345
        self.assertFileEqual('c\na\n', 'this/file')
346
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
347
    def test_weave_cannot_reverse_cherrypick(self):
348
        this_tree, other_tree = self.prepare_cherrypick()
349
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
350
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
351
        merger.merge_type = _mod_merge.WeaveMerger
352
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
353
354
    def test_merge3_can_reverse_cherrypick(self):
355
        this_tree, other_tree = self.prepare_cherrypick()
356
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
357
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
358
        merger.merge_type = _mod_merge.Merge3Merger
359
        merger.do_merge()
360
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
361
    def test_merge3_will_detect_cherrypick(self):
362
        this_tree = self.make_branch_and_tree('this')
363
        self.build_tree_contents([('this/file', "a\n")])
364
        this_tree.add('file')
365
        this_tree.commit('rev1')
366
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
367
        self.build_tree_contents([('other/file', "a\nb\n")])
368
        other_tree.commit('rev2b', rev_id='rev2b')
369
        self.build_tree_contents([('other/file', "a\nb\nc\n")])
370
        other_tree.commit('rev3b', rev_id='rev3b')
371
        this_tree.lock_write()
372
        self.addCleanup(this_tree.unlock)
373
374
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
375
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
376
        merger.merge_type = _mod_merge.Merge3Merger
377
        merger.do_merge()
378
        self.assertFileEqual('a\n'
379
                             '<<<<<<< TREE\n'
380
                             '=======\n'
381
                             'c\n'
382
                             '>>>>>>> MERGE-SOURCE\n',
383
                             'this/file')
384
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
385
    def test_make_merger(self):
386
        this_tree = self.make_branch_and_tree('this')
387
        this_tree.commit('rev1', rev_id='rev1')
388
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
389
        this_tree.commit('rev2', rev_id='rev2a')
390
        other_tree.commit('rev2', rev_id='rev2b')
391
        this_tree.lock_write()
392
        self.addCleanup(this_tree.unlock)
393
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress,
394
            this_tree, 'rev2b', other_branch=other_tree.branch)
395
        merger.merge_type = _mod_merge.Merge3Merger
396
        tree_merger = merger.make_merger()
397
        self.assertIs(_mod_merge.Merge3Merger, tree_merger.__class__)
398
        self.assertEqual('rev2b', tree_merger.other_tree.get_revision_id())
399
        self.assertEqual('rev1', tree_merger.base_tree.get_revision_id())
400
401
    def test_make_preview_transform(self):
402
        this_tree = self.make_branch_and_tree('this')
403
        self.build_tree_contents([('this/file', '1\n')])
404
        this_tree.add('file', 'file-id')
405
        this_tree.commit('rev1', rev_id='rev1')
406
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
407
        self.build_tree_contents([('this/file', '1\n2a\n')])
408
        this_tree.commit('rev2', rev_id='rev2a')
409
        self.build_tree_contents([('other/file', '2b\n1\n')])
410
        other_tree.commit('rev2', rev_id='rev2b')
411
        this_tree.lock_write()
412
        self.addCleanup(this_tree.unlock)
413
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
414
            this_tree, 'rev2b', other_branch=other_tree.branch)
415
        merger.merge_type = _mod_merge.Merge3Merger
416
        tree_merger = merger.make_merger()
417
        tt = tree_merger.make_preview_transform()
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
418
        self.addCleanup(tt.finalize)
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
419
        preview_tree = tt.get_preview_tree()
420
        tree_file = this_tree.get_file('file-id')
421
        try:
422
            self.assertEqual('1\n2a\n', tree_file.read())
423
        finally:
424
            tree_file.close()
425
        preview_file = preview_tree.get_file('file-id')
426
        try:
427
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
428
        finally:
429
            preview_file.close()
430
3008.1.22 by Aaron Bentley
Get do_merge under test
431
    def test_do_merge(self):
432
        this_tree = self.make_branch_and_tree('this')
433
        self.build_tree_contents([('this/file', '1\n')])
434
        this_tree.add('file', 'file-id')
435
        this_tree.commit('rev1', rev_id='rev1')
436
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
437
        self.build_tree_contents([('this/file', '1\n2a\n')])
438
        this_tree.commit('rev2', rev_id='rev2a')
439
        self.build_tree_contents([('other/file', '2b\n1\n')])
440
        other_tree.commit('rev2', rev_id='rev2b')
441
        this_tree.lock_write()
442
        self.addCleanup(this_tree.unlock)
443
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
444
            this_tree, 'rev2b', other_branch=other_tree.branch)
445
        merger.merge_type = _mod_merge.Merge3Merger
446
        tree_merger = merger.make_merger()
447
        tt = tree_merger.do_merge()
448
        tree_file = this_tree.get_file('file-id')
449
        try:
450
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
451
        finally:
452
            tree_file.close()
453
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
454
    def test_merge_add_into_deleted_root(self):
455
        # Yes, people actually do this.  And report bugs if it breaks.
456
        source = self.make_branch_and_tree('source', format='rich-root-pack')
457
        self.build_tree(['source/foo/'])
458
        source.add('foo', 'foo-id')
459
        source.commit('Add foo')
460
        target = source.bzrdir.sprout('target').open_workingtree()
461
        subtree = target.extract('foo-id')
462
        subtree.commit('Delete root')
463
        self.build_tree(['source/bar'])
464
        source.add('bar', 'bar-id')
465
        source.commit('Add bar')
466
        subtree.merge_from_branch(source.branch)
467
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
468
469
class TestPlanMerge(TestCaseWithMemoryTransport):
470
471
    def setUp(self):
472
        TestCaseWithMemoryTransport.setUp(self)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
473
        mapper = versionedfile.PrefixMapper()
474
        factory = knit.make_file_factory(True, mapper)
475
        self.vf = factory(self.get_transport())
476
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root')
477
        self.plan_merge_vf.fallback_versionedfiles.append(self.vf)
478
479
    def add_version(self, key, parents, text):
480
        self.vf.add_lines(key, parents, [c+'\n' for c in text])
481
3514.2.10 by John Arbash Meinel
Handle more edge cases.
482
    def add_rev(self, prefix, revision_id, parents, text):
483
        self.add_version((prefix, revision_id), [(prefix, p) for p in parents],
484
                         text)
485
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
486
    def add_uncommitted_version(self, key, parents, text):
487
        self.plan_merge_vf.add_lines(key, parents,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
488
                                     [c+'\n' for c in text])
489
490
    def setup_plan_merge(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
491
        self.add_rev('root', 'A', [], 'abc')
492
        self.add_rev('root', 'B', ['A'], 'acehg')
493
        self.add_rev('root', 'C', ['A'], 'fabg')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
494
        return _PlanMerge('B', 'C', self.plan_merge_vf, ('root',))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
495
496
    def setup_plan_merge_uncommitted(self):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
497
        self.add_version(('root', 'A'), [], 'abc')
498
        self.add_uncommitted_version(('root', 'B:'), [('root', 'A')], 'acehg')
499
        self.add_uncommitted_version(('root', 'C:'), [('root', 'A')], 'fabg')
500
        return _PlanMerge('B:', 'C:', self.plan_merge_vf, ('root',))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
501
502
    def test_unique_lines(self):
503
        plan = self.setup_plan_merge()
504
        self.assertEqual(plan._unique_lines(
505
            plan._get_matching_blocks('B', 'C')),
506
            ([1, 2, 3], [0, 2]))
507
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
508
    def test_plan_merge(self):
509
        self.setup_plan_merge()
510
        plan = self.plan_merge_vf.plan_merge('B', 'C')
511
        self.assertEqual([
512
                          ('new-b', 'f\n'),
513
                          ('unchanged', 'a\n'),
514
                          ('killed-a', 'b\n'),
515
                          ('killed-b', 'c\n'),
516
                          ('new-a', 'e\n'),
517
                          ('new-a', 'h\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
518
                          ('new-a', 'g\n'),
519
                          ('new-b', 'g\n')],
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
520
                         list(plan))
521
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
522
    def test_plan_merge_cherrypick(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
523
        self.add_rev('root', 'A', [], 'abc')
524
        self.add_rev('root', 'B', ['A'], 'abcde')
525
        self.add_rev('root', 'C', ['A'], 'abcefg')
526
        self.add_rev('root', 'D', ['A', 'B', 'C'], 'abcdegh')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
527
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf, ('root',))
3514.2.11 by John Arbash Meinel
Shortcut the case when one revision is in the ancestry of the other.
528
        # We shortcut when one text supersedes the other in the per-file graph.
529
        # We don't actually need to compare the texts at this point.
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
530
        self.assertEqual([
3514.2.11 by John Arbash Meinel
Shortcut the case when one revision is in the ancestry of the other.
531
                          ('new-b', 'a\n'),
532
                          ('new-b', 'b\n'),
533
                          ('new-b', 'c\n'),
534
                          ('new-b', 'd\n'),
535
                          ('new-b', 'e\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
536
                          ('new-b', 'g\n'),
537
                          ('new-b', 'h\n')],
538
                          list(my_plan.plan_merge()))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
539
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
540
    def test_plan_merge_no_common_ancestor(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
541
        self.add_rev('root', 'A', [], 'abc')
542
        self.add_rev('root', 'B', [], 'xyz')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
543
        my_plan = _PlanMerge('A', 'B', self.plan_merge_vf, ('root',))
544
        self.assertEqual([
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
545
                          ('new-a', 'a\n'),
546
                          ('new-a', 'b\n'),
547
                          ('new-a', 'c\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
548
                          ('new-b', 'x\n'),
549
                          ('new-b', 'y\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
550
                          ('new-b', 'z\n')],
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
551
                          list(my_plan.plan_merge()))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
552
3514.2.10 by John Arbash Meinel
Handle more edge cases.
553
    def test_plan_merge_tail_ancestors(self):
554
        # The graph looks like this:
555
        #       A       # Common to all ancestors
556
        #      / \
557
        #     B   C     # Ancestors of E, only common to one side
558
        #     |\ /|
559
        #     D E F     # D, F are unique to G, H respectively
560
        #     |/ \|     # E is the LCA for G & H, and the unique LCA for
561
        #     G   H     # I, J
562
        #     |\ /|
563
        #     | X |
564
        #     |/ \|
565
        #     I   J     # criss-cross merge of G, H
566
        #
567
        # In this situation, a simple pruning of ancestors of E will leave D &
568
        # F "dangling", which looks like they introduce lines different from
569
        # the ones in E, but in actuality C&B introduced the lines, and they
570
        # are already present in E
571
572
        # Introduce the base text
573
        self.add_rev('root', 'A', [], 'abc')
574
        # Introduces a new line B
575
        self.add_rev('root', 'B', ['A'], 'aBbc')
576
        # Introduces a new line C
577
        self.add_rev('root', 'C', ['A'], 'abCc')
578
        # Introduce new line D
579
        self.add_rev('root', 'D', ['B'], 'DaBbc')
580
        # Merges B and C by just incorporating both
581
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
582
        # Introduce new line F
583
        self.add_rev('root', 'F', ['C'], 'abCcF')
584
        # Merge D & E by just combining the texts
585
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
586
        # Merge F & E by just combining the texts
587
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
588
        # Merge G & H by just combining texts
589
        self.add_rev('root', 'I', ['G', 'H'], 'DaBbCcF')
590
        # Merge G & H but supersede an old line in B
591
        self.add_rev('root', 'J', ['H', 'G'], 'DaJbCcF')
592
        plan = self.plan_merge_vf.plan_merge('I', 'J')
593
        self.assertEqual([
594
                          ('unchanged', 'D\n'),
595
                          ('unchanged', 'a\n'),
596
                          ('killed-b', 'B\n'),
597
                          ('new-b', 'J\n'),
598
                          ('unchanged', 'b\n'),
599
                          ('unchanged', 'C\n'),
600
                          ('unchanged', 'c\n'),
601
                          ('unchanged', 'F\n')],
602
                         list(plan))
603
604
    def test_plan_merge_tail_triple_ancestors(self):
605
        # The graph looks like this:
606
        #       A       # Common to all ancestors
607
        #      / \
608
        #     B   C     # Ancestors of E, only common to one side
609
        #     |\ /|
610
        #     D E F     # D, F are unique to G, H respectively
611
        #     |/|\|     # E is the LCA for G & H, and the unique LCA for
612
        #     G Q H     # I, J
613
        #     |\ /|     # Q is just an extra node which is merged into both
614
        #     | X |     # I and J
615
        #     |/ \|
616
        #     I   J     # criss-cross merge of G, H
617
        #
618
        # This is the same as the test_plan_merge_tail_ancestors, except we add
619
        # a third LCA that doesn't add new lines, but will trigger our more
620
        # involved ancestry logic
621
622
        self.add_rev('root', 'A', [], 'abc')
623
        self.add_rev('root', 'B', ['A'], 'aBbc')
624
        self.add_rev('root', 'C', ['A'], 'abCc')
625
        self.add_rev('root', 'D', ['B'], 'DaBbc')
626
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
627
        self.add_rev('root', 'F', ['C'], 'abCcF')
628
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
629
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
630
        self.add_rev('root', 'Q', ['E'], 'aBbCc')
631
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DaBbCcF')
632
        # Merge G & H but supersede an old line in B
633
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DaJbCcF')
634
        plan = self.plan_merge_vf.plan_merge('I', 'J')
635
        self.assertEqual([
636
                          ('unchanged', 'D\n'),
637
                          ('unchanged', 'a\n'),
638
                          ('killed-b', 'B\n'),
639
                          ('new-b', 'J\n'),
640
                          ('unchanged', 'b\n'),
641
                          ('unchanged', 'C\n'),
642
                          ('unchanged', 'c\n'),
643
                          ('unchanged', 'F\n')],
644
                         list(plan))
645
3514.2.14 by John Arbash Meinel
Bring in the code to collapse linear portions of the graph.
646
    def test_plan_merge_2_tail_triple_ancestors(self):
647
        # The graph looks like this:
648
        #     A   B     # 2 tails going back to NULL
649
        #     |\ /|
650
        #     D E F     # D, is unique to G, F to H
651
        #     |/|\|     # E is the LCA for G & H, and the unique LCA for
652
        #     G Q H     # I, J
653
        #     |\ /|     # Q is just an extra node which is merged into both
654
        #     | X |     # I and J
655
        #     |/ \|
656
        #     I   J     # criss-cross merge of G, H (and Q)
657
        #
658
659
        # This is meant to test after hitting a 3-way LCA, and multiple tail
660
        # ancestors (only have NULL_REVISION in common)
661
662
        self.add_rev('root', 'A', [], 'abc')
663
        self.add_rev('root', 'B', [], 'def')
664
        self.add_rev('root', 'D', ['A'], 'Dabc')
665
        self.add_rev('root', 'E', ['A', 'B'], 'abcdef')
666
        self.add_rev('root', 'F', ['B'], 'defF')
667
        self.add_rev('root', 'G', ['D', 'E'], 'Dabcdef')
668
        self.add_rev('root', 'H', ['F', 'E'], 'abcdefF')
669
        self.add_rev('root', 'Q', ['E'], 'abcdef')
670
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DabcdefF')
671
        # Merge G & H but supersede an old line in B
672
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DabcdJfF')
673
        plan = self.plan_merge_vf.plan_merge('I', 'J')
674
        self.assertEqual([
675
                          ('unchanged', 'D\n'),
676
                          ('unchanged', 'a\n'),
677
                          ('unchanged', 'b\n'),
678
                          ('unchanged', 'c\n'),
679
                          ('unchanged', 'd\n'),
680
                          ('killed-b', 'e\n'),
681
                          ('new-b', 'J\n'),
682
                          ('unchanged', 'f\n'),
683
                          ('unchanged', 'F\n')],
684
                         list(plan))
685
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
686
    def test_plan_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
687
        self.setup_plan_merge_uncommitted()
688
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
689
        self.assertEqual([
690
                          ('new-b', 'f\n'),
691
                          ('unchanged', 'a\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
692
                          ('killed-a', 'b\n'),
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
693
                          ('killed-b', 'c\n'),
694
                          ('new-a', 'e\n'),
695
                          ('new-a', 'h\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
696
                          ('new-a', 'g\n'),
697
                          ('new-b', 'g\n')],
698
                         list(plan))
699
700
    def test_plan_merge_insert_order(self):
701
        """Weave merges are sensitive to the order of insertion.
702
        
703
        Specifically for overlapping regions, it effects which region gets put
704
        'first'. And when a user resolves an overlapping merge, if they use the
705
        same ordering, then the lines match the parents, if they don't only
706
        *some* of the lines match.
707
        """
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
708
        self.add_rev('root', 'A', [], 'abcdef')
709
        self.add_rev('root', 'B', ['A'], 'abwxcdef')
710
        self.add_rev('root', 'C', ['A'], 'abyzcdef')
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
711
        # Merge, and resolve the conflict by adding *both* sets of lines
712
        # If we get the ordering wrong, these will look like new lines in D,
713
        # rather than carried over from B, C
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
714
        self.add_rev('root', 'D', ['B', 'C'],
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
715
                         'abwxyzcdef')
716
        # Supersede the lines in B and delete the lines in C, which will
717
        # conflict if they are treated as being in D
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
718
        self.add_rev('root', 'E', ['C', 'B'],
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
719
                         'abnocdef')
720
        # Same thing for the lines in C
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
721
        self.add_rev('root', 'F', ['C'], 'abpqcdef')
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
722
        plan = self.plan_merge_vf.plan_merge('D', 'E')
723
        self.assertEqual([
724
                          ('unchanged', 'a\n'),
725
                          ('unchanged', 'b\n'),
726
                          ('killed-b', 'w\n'),
727
                          ('killed-b', 'x\n'),
728
                          ('killed-b', 'y\n'),
729
                          ('killed-b', 'z\n'),
730
                          ('new-b', 'n\n'),
731
                          ('new-b', 'o\n'),
732
                          ('unchanged', 'c\n'),
733
                          ('unchanged', 'd\n'),
734
                          ('unchanged', 'e\n'),
735
                          ('unchanged', 'f\n')],
736
                         list(plan))
737
        plan = self.plan_merge_vf.plan_merge('E', 'D')
738
        # Going in the opposite direction shows the effect of the opposite plan
739
        self.assertEqual([
740
                          ('unchanged', 'a\n'),
741
                          ('unchanged', 'b\n'),
742
                          ('new-b', 'w\n'),
743
                          ('new-b', 'x\n'),
744
                          ('killed-a', 'y\n'),
745
                          ('killed-a', 'z\n'),
746
                          ('killed-both', 'w\n'),
747
                          ('killed-both', 'x\n'),
748
                          ('new-a', 'n\n'),
749
                          ('new-a', 'o\n'),
750
                          ('unchanged', 'c\n'),
751
                          ('unchanged', 'd\n'),
752
                          ('unchanged', 'e\n'),
753
                          ('unchanged', 'f\n')],
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
754
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
755
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
756
    def test_plan_merge_criss_cross(self):
757
        # This is specificly trying to trigger problems when using limited
758
        # ancestry and weaves. The ancestry graph looks like:
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
759
        #       XX      unused ancestor, should not show up in the weave
760
        #       |
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
761
        #       A       Unique LCA
762
        #       |\
763
        #       B \     Introduces a line 'foo'
764
        #      / \ \
765
        #     C   D E   C & D both have 'foo', E has different changes
766
        #     |\ /| |
767
        #     | X | |
768
        #     |/ \|/
769
        #     F   G      All of C, D, E are merged into F and G, so they are
770
        #                all common ancestors.
771
        #
772
        # The specific issue with weaves:
773
        #   B introduced a text ('foo') that is present in both C and D.
774
        #   If we do not include B (because it isn't an ancestor of E), then
775
        #   the A=>C and A=>D look like both sides independently introduce the
776
        #   text ('foo'). If F does not modify the text, it would still appear
777
        #   to have deleted on of the versions from C or D. If G then modifies
778
        #   'foo', it should appear as superseding the value in F (since it
779
        #   came from B), rather than conflict because of the resolution during
780
        #   C & D.
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
781
        self.add_rev('root', 'XX', [], 'qrs')
782
        self.add_rev('root', 'A', ['XX'], 'abcdef')
783
        self.add_rev('root', 'B', ['A'], 'axcdef')
784
        self.add_rev('root', 'C', ['B'], 'axcdefg')
785
        self.add_rev('root', 'D', ['B'], 'haxcdef')
786
        self.add_rev('root', 'E', ['A'], 'abcdyf')
787
        # Simple combining of all texts
788
        self.add_rev('root', 'F', ['C', 'D', 'E'], 'haxcdyfg')
789
        # combine and supersede 'x'
790
        self.add_rev('root', 'G', ['C', 'D', 'E'], 'hazcdyfg')
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
791
        plan = self.plan_merge_vf.plan_merge('F', 'G')
792
        self.assertEqual([
793
                          ('unchanged', 'h\n'),
794
                          ('unchanged', 'a\n'),
3514.2.7 by John Arbash Meinel
Fix the failing test by implementing the fallback logic.
795
                          ('killed-base', 'b\n'),
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
796
                          ('killed-b', 'x\n'),
797
                          ('new-b', 'z\n'),
798
                          ('unchanged', 'c\n'),
799
                          ('unchanged', 'd\n'),
800
                          ('killed-base', 'e\n'),
801
                          ('unchanged', 'y\n'),
802
                          ('unchanged', 'f\n'),
803
                          ('unchanged', 'g\n')],
804
                         list(plan))
805
3514.2.12 by John Arbash Meinel
Start refactoring into helper functions
806
    def assertRemoveExternalReferences(self, filtered_parent_map,
807
                                       child_map, tails, parent_map):
808
        """Assert results for _PlanMerge._remove_external_references."""
809
        (act_filtered_parent_map, act_child_map,
810
         act_tails) = _PlanMerge._remove_external_references(parent_map)
811
812
        # The parent map *should* preserve ordering, but the ordering of
813
        # children is not strictly defined
814
        # child_map = dict((k, sorted(children))
815
        #                  for k, children in child_map.iteritems())
816
        # act_child_map = dict(k, sorted(children)
817
        #                      for k, children in act_child_map.iteritems())
818
        self.assertEqual(filtered_parent_map, act_filtered_parent_map)
819
        self.assertEqual(child_map, act_child_map)
820
        self.assertEqual(sorted(tails), sorted(act_tails))
821
822
    def test__remove_external_references(self):
823
        # First, nothing to remove
824
        self.assertRemoveExternalReferences({3: [2], 2: [1], 1: []},
825
            {1: [2], 2: [3], 3: []}, [1], {3: [2], 2: [1], 1: []})
826
        # The reverse direction
827
        self.assertRemoveExternalReferences({1: [2], 2: [3], 3: []},
828
            {3: [2], 2: [1], 1: []}, [3], {1: [2], 2: [3], 3: []})
829
        # Extra references
830
        self.assertRemoveExternalReferences({3: [2], 2: [1], 1: []},
831
            {1: [2], 2: [3], 3: []}, [1], {3: [2, 4], 2: [1, 5], 1: [6]})
832
        # Multiple tails
833
        self.assertRemoveExternalReferences(
834
            {4: [2, 3], 3: [], 2: [1], 1: []},
835
            {1: [2], 2: [4], 3: [4], 4: []},
836
            [1, 3],
837
            {4: [2, 3], 3: [5], 2: [1], 1: [6]})
838
        # Multiple children
839
        self.assertRemoveExternalReferences(
840
            {1: [3], 2: [3, 4], 3: [], 4: []},
841
            {1: [], 2: [], 3: [1, 2], 4: [2]},
842
            [3, 4],
843
            {1: [3], 2: [3, 4], 3: [5], 4: []})
844
3514.2.13 by John Arbash Meinel
Add the ability to prune extra tails from the parent_map.
845
    def assertPruneTails(self, pruned_map, tails, parent_map):
846
        child_map = {}
847
        for key, parent_keys in parent_map.iteritems():
848
            child_map.setdefault(key, [])
849
            for pkey in parent_keys:
850
                child_map.setdefault(pkey, []).append(key)
851
        _PlanMerge._prune_tails(parent_map, child_map, tails)
852
        self.assertEqual(pruned_map, parent_map)
853
854
    def test__prune_tails(self):
855
        # Nothing requested to prune
856
        self.assertPruneTails({1: [], 2: [], 3: []}, [],
857
                              {1: [], 2: [], 3: []})
858
        # Prune a single entry
859
        self.assertPruneTails({1: [], 3: []}, [2],
860
                              {1: [], 2: [], 3: []})
861
        # Prune a chain
862
        self.assertPruneTails({1: []}, [3],
863
                              {1: [], 2: [3], 3: []})
864
        # Prune a chain with a diamond
865
        self.assertPruneTails({1: []}, [5],
866
                              {1: [], 2: [3, 4], 3: [5], 4: [5], 5: []})
867
        # Prune a partial chain
868
        self.assertPruneTails({1: [6], 6:[]}, [5],
869
                              {1: [2, 6], 2: [3, 4], 3: [5], 4: [5], 5: [],
870
                               6: []})
871
        # Prune a chain with multiple tips, that pulls out intermediates
872
        self.assertPruneTails({1:[3], 3:[]}, [4, 5],
873
                              {1: [2, 3], 2: [4, 5], 3: [], 4:[], 5:[]})
874
        self.assertPruneTails({1:[3], 3:[]}, [5, 4],
875
                              {1: [2, 3], 2: [4, 5], 3: [], 4:[], 5:[]})
876
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
877
    def test_subtract_plans(self):
878
        old_plan = [
879
        ('unchanged', 'a\n'),
880
        ('new-a', 'b\n'),
881
        ('killed-a', 'c\n'),
882
        ('new-b', 'd\n'),
883
        ('new-b', 'e\n'),
884
        ('killed-b', 'f\n'),
885
        ('killed-b', 'g\n'),
886
        ]
887
        new_plan = [
888
        ('unchanged', 'a\n'),
889
        ('new-a', 'b\n'),
890
        ('killed-a', 'c\n'),
891
        ('new-b', 'd\n'),
892
        ('new-b', 'h\n'),
893
        ('killed-b', 'f\n'),
894
        ('killed-b', 'i\n'),
895
        ]
896
        subtracted_plan = [
897
        ('unchanged', 'a\n'),
898
        ('new-a', 'b\n'),
899
        ('killed-a', 'c\n'),
900
        ('new-b', 'h\n'),
901
        ('unchanged', 'f\n'),
902
        ('killed-b', 'i\n'),
903
        ]
904
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
905
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
906
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
907
    def setup_merge_with_base(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
908
        self.add_rev('root', 'COMMON', [], 'abc')
909
        self.add_rev('root', 'THIS', ['COMMON'], 'abcd')
910
        self.add_rev('root', 'BASE', ['COMMON'], 'eabc')
911
        self.add_rev('root', 'OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
912
913
    def test_plan_merge_with_base(self):
914
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
915
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
916
        self.assertEqual([('unchanged', 'a\n'),
917
                          ('new-b', 'f\n'),
918
                          ('unchanged', 'b\n'),
919
                          ('killed-b', 'c\n'),
920
                          ('new-a', 'd\n')
921
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
922
923
    def test_plan_lca_merge(self):
924
        self.setup_plan_merge()
925
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
926
        self.assertEqual([
927
                          ('new-b', 'f\n'),
928
                          ('unchanged', 'a\n'),
929
                          ('killed-b', 'c\n'),
930
                          ('new-a', 'e\n'),
931
                          ('new-a', 'h\n'),
932
                          ('killed-a', 'b\n'),
933
                          ('unchanged', 'g\n')],
934
                         list(plan))
935
936
    def test_plan_lca_merge_uncommitted_files(self):
937
        self.setup_plan_merge_uncommitted()
938
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
939
        self.assertEqual([
940
                          ('new-b', 'f\n'),
941
                          ('unchanged', 'a\n'),
942
                          ('killed-b', 'c\n'),
943
                          ('new-a', 'e\n'),
944
                          ('new-a', 'h\n'),
945
                          ('killed-a', 'b\n'),
946
                          ('unchanged', 'g\n')],
947
                         list(plan))
948
949
    def test_plan_lca_merge_with_base(self):
950
        self.setup_merge_with_base()
951
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
952
        self.assertEqual([('unchanged', 'a\n'),
953
                          ('new-b', 'f\n'),
954
                          ('unchanged', 'b\n'),
955
                          ('killed-b', 'c\n'),
956
                          ('new-a', 'd\n')
957
                         ], list(plan))
958
959
    def test_plan_lca_merge_with_criss_cross(self):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
960
        self.add_version(('root', 'ROOT'), [], 'abc')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
961
        # each side makes a change
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
962
        self.add_version(('root', 'REV1'), [('root', 'ROOT')], 'abcd')
963
        self.add_version(('root', 'REV2'), [('root', 'ROOT')], 'abce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
964
        # both sides merge, discarding others' changes
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
965
        self.add_version(('root', 'LCA1'),
966
            [('root', 'REV1'), ('root', 'REV2')], 'abcd')
967
        self.add_version(('root', 'LCA2'),
968
            [('root', 'REV1'), ('root', 'REV2')], 'fabce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
969
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
970
        self.assertEqual([('new-b', 'f\n'),
971
                          ('unchanged', 'a\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
972
                          ('unchanged', 'b\n'),
973
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
974
                          ('conflicted-a', 'd\n'),
975
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
976
                         ], list(plan))
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
977
3287.17.1 by John Arbash Meinel
Fix bug #235715 by using the empty list as the text for a base of NULL_REVISION.
978
    def test_plan_lca_merge_with_null(self):
3350.6.5 by Robert Collins
Update to bzr.dev.
979
        self.add_version(('root', 'A'), [], 'ab')
980
        self.add_version(('root', 'B'), [], 'bc')
3287.17.1 by John Arbash Meinel
Fix bug #235715 by using the empty list as the text for a base of NULL_REVISION.
981
        plan = self.plan_merge_vf.plan_lca_merge('A', 'B')
982
        self.assertEqual([('new-a', 'a\n'),
983
                          ('unchanged', 'b\n'),
984
                          ('new-b', 'c\n'),
985
                         ], list(plan))
986
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
987
    def test_plan_merge_with_delete_and_change(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
988
        self.add_rev('root', 'C', [], 'a')
989
        self.add_rev('root', 'A', ['C'], 'b')
990
        self.add_rev('root', 'B', ['C'], '')
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
991
        plan = self.plan_merge_vf.plan_merge('A', 'B')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
992
        self.assertEqual([('killed-both', 'a\n'),
993
                          ('new-a', 'b\n'),
994
                         ], list(plan))
995
996
    def test_plan_merge_with_move_and_change(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
997
        self.add_rev('root', 'C', [], 'abcd')
998
        self.add_rev('root', 'A', ['C'], 'acbd')
999
        self.add_rev('root', 'B', ['C'], 'aBcd')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1000
        plan = self.plan_merge_vf.plan_merge('A', 'B')
1001
        self.assertEqual([('unchanged', 'a\n'),
1002
                          ('new-a', 'c\n'),
1003
                          ('killed-b', 'b\n'),
1004
                          ('new-b', 'B\n'),
1005
                          ('killed-a', 'c\n'),
1006
                          ('unchanged', 'd\n'),
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1007
                         ], list(plan))
1008
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
1009
1010
class TestMergeImplementation(object):
1011
1012
    def do_merge(self, target_tree, source_tree, **kwargs):
1013
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
1014
            target_tree, source_tree.last_revision(),
1015
            other_branch=source_tree.branch)
1016
        merger.merge_type=self.merge_type
1017
        for name, value in kwargs.items():
1018
            setattr(merger, name, value)
1019
        merger.do_merge()
1020
1021
    def test_merge_specific_file(self):
1022
        this_tree = self.make_branch_and_tree('this')
1023
        this_tree.lock_write()
1024
        self.addCleanup(this_tree.unlock)
1025
        self.build_tree_contents([
1026
            ('this/file1', 'a\nb\n'),
1027
            ('this/file2', 'a\nb\n')
1028
        ])
1029
        this_tree.add(['file1', 'file2'])
1030
        this_tree.commit('Added files')
1031
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
1032
        self.build_tree_contents([
1033
            ('other/file1', 'a\nb\nc\n'),
1034
            ('other/file2', 'a\nb\nc\n')
1035
        ])
1036
        other_tree.commit('modified both')
1037
        self.build_tree_contents([
1038
            ('this/file1', 'd\na\nb\n'),
1039
            ('this/file2', 'd\na\nb\n')
1040
        ])
1041
        this_tree.commit('modified both')
1042
        self.do_merge(this_tree, other_tree, interesting_files=['file1'])
1043
        self.assertFileEqual('d\na\nb\nc\n', 'this/file1')
1044
        self.assertFileEqual('d\na\nb\n', 'this/file2')
1045
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1046
    def test_merge_move_and_change(self):
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1047
        this_tree = self.make_branch_and_tree('this')
1048
        this_tree.lock_write()
1049
        self.addCleanup(this_tree.unlock)
1050
        self.build_tree_contents([
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1051
            ('this/file1', 'line 1\nline 2\nline 3\nline 4\n'),
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1052
        ])
1053
        this_tree.add('file1',)
1054
        this_tree.commit('Added file')
1055
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
1056
        self.build_tree_contents([
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1057
            ('other/file1', 'line 1\nline 2 to 2.1\nline 3\nline 4\n'),
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1058
        ])
3514.2.16 by John Arbash Meinel
Review feedback from Ian.
1059
        other_tree.commit('Changed 2 to 2.1')
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1060
        self.build_tree_contents([
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1061
            ('this/file1', 'line 1\nline 3\nline 2\nline 4\n'),
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1062
        ])
3514.2.16 by John Arbash Meinel
Review feedback from Ian.
1063
        this_tree.commit('Swapped 2 & 3')
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1064
        self.do_merge(this_tree, other_tree)
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1065
        self.assertFileEqual('line 1\n'
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1066
            '<<<<<<< TREE\n'
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1067
            'line 3\n'
1068
            'line 2\n'
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1069
            '=======\n'
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1070
            'line 2 to 2.1\n'
1071
            'line 3\n'
1072
            '>>>>>>> MERGE-SOURCE\n'
1073
            'line 4\n', 'this/file1')
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1074
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
1075
1076
class TestMerge3Merge(TestCaseWithTransport, TestMergeImplementation):
1077
1078
    merge_type = _mod_merge.Merge3Merger
1079
1080
1081
class TestWeaveMerge(TestCaseWithTransport, TestMergeImplementation):
1082
1083
    merge_type = _mod_merge.WeaveMerger
1084
1085
1086
class TestLCAMerge(TestCaseWithTransport, TestMergeImplementation):
1087
1088
    merge_type = _mod_merge.LCAMerger
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1089
1090
    def test_merge_move_and_change(self):
1091
        self.expectFailure("lca merge doesn't conflict for move and change",
1092
            super(TestLCAMerge, self).test_merge_move_and_change)
3514.4.6 by John Arbash Meinel
Merge in the BranchBuilder updates, which brings in a newer bzr.dev
1093
3514.4.1 by John Arbash Meinel
Update Merger to set a flag when we encounter a criss-cross merge.
1094
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1095
class LoggingMerger(object):
1096
    # These seem to be the required attributes
1097
    requires_base = False
1098
    supports_reprocess = False
1099
    supports_show_base = False
1100
    supports_cherrypick = False
1101
    # We intentionally do not define supports_lca_trees
1102
1103
    def __init__(self, *args, **kwargs):
1104
        self.args = args
1105
        self.kwargs = kwargs
1106
1107
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1108
class TestMergerBase(TestCaseWithMemoryTransport):
3514.4.3 by John Arbash Meinel
Switch to using an in-memory tree when possible
1109
    """Tests for Merger that can be done without hitting disk."""
3514.4.1 by John Arbash Meinel
Update Merger to set a flag when we encounter a criss-cross merge.
1110
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1111
    def get_builder(self):
1112
        builder = self.make_branch_builder('path')
1113
        builder.start_series()
1114
        self.addCleanup(builder.finish_series)
1115
        return builder
1116
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1117
    def setup_simple_graph(self):
1118
        """Create a simple 3-node graph.
1119
                A
1120
                |\\
1121
                B C
1122
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1123
        :return: A BranchBuilder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1124
        """
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1125
        builder = self.get_builder()
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1126
        builder.build_snapshot('A-id', None,
1127
            [('add', ('', None, 'directory', None))])
1128
        builder.build_snapshot('C-id', ['A-id'], [])
1129
        builder.build_snapshot('B-id', ['A-id'], [])
1130
        return builder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1131
1132
    def setup_criss_cross_graph(self):
1133
        """Create a 5-node graph with a criss-cross.
1134
                A
1135
                |\\
1136
                B C
1137
                |X|
1138
                D E
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1139
        :return: A BranchBuilder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1140
        """
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1141
        builder = self.setup_simple_graph()
1142
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1143
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1144
        return builder
1145
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1146
    def make_Merger(self, builder, other_revision_id):
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1147
        """Make a Merger object from a branch builder"""
1148
        mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1149
        mem_tree.lock_write()
1150
        self.addCleanup(mem_tree.unlock)
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1151
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1152
            mem_tree, other_revision_id)
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1153
        merger.merge_type = _mod_merge.Merge3Merger
1154
        return merger
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1155
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1156
1157
class TestMergerInMemory(TestMergerBase):
1158
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1159
    def test_find_base(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1160
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1161
        self.assertEqual('A-id', merger.base_rev_id)
1162
        self.assertFalse(merger._is_criss_cross)
1163
        self.assertIs(None, merger._lca_trees)
1164
1165
    def test_find_base_criss_cross(self):
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1166
        builder = self.setup_criss_cross_graph()
1167
        merger = self.make_Merger(builder, 'E-id')
3514.4.1 by John Arbash Meinel
Update Merger to set a flag when we encounter a criss-cross merge.
1168
        self.assertEqual('A-id', merger.base_rev_id)
1169
        self.assertTrue(merger._is_criss_cross)
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1170
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1171
                                            for t in merger._lca_trees])
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1172
        # If we swap the order, we should get a different lca order
1173
        builder.build_snapshot('F-id', ['E-id'], [])
1174
        merger = self.make_Merger(builder, 'D-id')
1175
        self.assertEqual(['C-id', 'B-id'], [t.get_revision_id()
1176
                                            for t in merger._lca_trees])
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1177
1178
    def test_no_criss_cross_passed_to_merge_type(self):
1179
        class LCATreesMerger(LoggingMerger):
1180
            supports_lca_trees = True
1181
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1182
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1183
        merger.merge_type = LCATreesMerger
1184
        merge_obj = merger.make_merger()
1185
        self.assertIsInstance(merge_obj, LCATreesMerger)
1186
        self.assertFalse('lca_trees' in merge_obj.kwargs)
1187
1188
    def test_criss_cross_passed_to_merge_type(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1189
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1190
        merger.merge_type = _mod_merge.Merge3Merger
1191
        merge_obj = merger.make_merger()
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1192
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1193
                                            for t in merger._lca_trees])
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1194
1195
    def test_criss_cross_not_supported_merge_type(self):
1196
        class NoLCATreesMerger(LoggingMerger):
1197
            # We intentionally do not define supports_lca_trees
1198
            pass
1199
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1200
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1201
        merger.merge_type = NoLCATreesMerger
1202
        merge_obj = merger.make_merger()
1203
        self.assertIsInstance(merge_obj, NoLCATreesMerger)
1204
        self.assertFalse('lca_trees' in merge_obj.kwargs)
1205
1206
    def test_criss_cross_unsupported_merge_type(self):
1207
        class UnsupportedLCATreesMerger(LoggingMerger):
1208
            supports_lca_trees = False
1209
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1210
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1211
        merger.merge_type = UnsupportedLCATreesMerger
1212
        merge_obj = merger.make_merger()
1213
        self.assertIsInstance(merge_obj, UnsupportedLCATreesMerger)
1214
        self.assertFalse('lca_trees' in merge_obj.kwargs)
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1215
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1216
1217
class TestMergerEntriesLCA(TestMergerBase):
1218
1219
    def make_merge_obj(self, builder, other_revision_id):
1220
        merger = self.make_Merger(builder, other_revision_id)
1221
        return merger.make_merger()
1222
        
1223
    def test_simple(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1224
        builder = self.get_builder()
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1225
        builder.build_snapshot('A-id', None,
1226
            [('add', (u'', 'a-root-id', 'directory', None)),
1227
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1228
        builder.build_snapshot('C-id', ['A-id'],
1229
            [('modify', ('a-id', 'a\nb\nC\nc\n'))])
1230
        builder.build_snapshot('B-id', ['A-id'],
1231
            [('modify', ('a-id', 'a\nB\nb\nc\n'))])
1232
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
1233
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))])
1234
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
1235
            [('modify', ('a-id', 'a\nB\nb\nC\nc\n'))])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1236
        merge_obj = self.make_merge_obj(builder, 'E-id')
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1237
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1238
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1239
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1240
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1241
        entries = list(merge_obj._entries_lca())
1242
1243
        # (file_id, changed, parents, names, executable)
1244
        # BASE, lca1, lca2, OTHER, THIS
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1245
        root_id = 'a-root-id'
3514.4.12 by John Arbash Meinel
add more filtering for when a directory hasn't actually changed.
1246
        self.assertEqual([('a-id', True,
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1247
                           ((root_id, [root_id, root_id]), root_id, root_id),
1248
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1249
                           ((False, [False, False]), False, False)),
1250
                         ], entries)
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1251
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1252
    def test_not_in_base(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1253
        # LCA's all have the same last-modified revision for the file, as do
1254
        # the tips, but the base has something different
1255
        #       A    base, doesn't have the file
1256
        #       |\ 
1257
        #       B C  B introduces 'foo', C introduces 'bar'
1258
        #       |X|
1259
        #       D E  D and E now both have 'foo' and 'bar'
1260
        #       |X|
1261
        #       F G  the files are now in F, G, D and E, but not in A
1262
        #            G modifies 'bar'
1263
            
1264
        builder = self.get_builder()
1265
        builder.build_snapshot('A-id', None,
1266
            [('add', (u'', 'a-root-id', 'directory', None))])
1267
        builder.build_snapshot('B-id', ['A-id'],
1268
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
1269
        builder.build_snapshot('C-id', ['A-id'],
1270
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))])
1271
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
1272
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))])
1273
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
1274
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))])
1275
        builder.build_snapshot('G-id', ['E-id', 'D-id'],
1276
            [('modify', (u'bar-id', 'd\ne\nf\nG\n'))])
1277
        builder.build_snapshot('F-id', ['D-id', 'E-id'], [])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1278
        merge_obj = self.make_merge_obj(builder, 'G-id')
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1279
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1280
        self.assertEqual(['D-id', 'E-id'], [t.get_revision_id()
1281
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1282
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1283
        entries = list(merge_obj._entries_lca())
1284
        root_id = 'a-root-id'
1285
        self.assertEqual([('bar-id', True,
1286
                           ((None, [root_id, root_id]), root_id, root_id),
1287
                           ((None, [u'bar', u'bar']), u'bar', u'bar'),
1288
                           ((None, [False, False]), False, False)),
1289
                         ], entries)
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1290
1291
    def test_not_in_this(self):
1292
        builder = self.get_builder()
1293
        builder.build_snapshot('A-id', None,
1294
            [('add', (u'', 'a-root-id', 'directory', None)),
1295
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1296
        builder.build_snapshot('B-id', ['A-id'],
1297
            [('modify', ('a-id', 'a\nB\nb\nc\n'))])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1298
        builder.build_snapshot('C-id', ['A-id'],
1299
            [('modify', ('a-id', 'a\nb\nC\nc\n'))])
1300
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
1301
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))])
1302
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
1303
            [('unversion', 'a-id')])
1304
        merge_obj = self.make_merge_obj(builder, 'E-id')
1305
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1306
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1307
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1308
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
1309
1310
        entries = list(merge_obj._entries_lca())
1311
        root_id = 'a-root-id'
1312
        self.assertEqual([('a-id', True,
1313
                           ((root_id, [root_id, root_id]), root_id, None),
1314
                           ((u'a', [u'a', u'a']), u'a', None),
1315
                           ((False, [False, False]), False, None)),
1316
                         ], entries)
1317
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1318
    def test_not_in_one_lca(self):
1319
        builder = self.get_builder()
1320
        builder.build_snapshot('A-id', None,
1321
            [('add', (u'', 'a-root-id', 'directory', None))])
1322
        builder.build_snapshot('B-id', ['A-id'], [])
1323
        builder.build_snapshot('C-id', ['A-id'],
1324
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1325
        builder.build_snapshot('E-id', ['C-id', 'B-id'], [])
1326
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
1327
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1328
        merge_obj = self.make_merge_obj(builder, 'E-id')
1329
1330
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1331
                                            for t in merge_obj._lca_trees])
1332
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
1333
1334
        entries = list(merge_obj._entries_lca())
1335
        root_id = 'a-root-id'
1336
        self.assertEqual([('a-id', True,
1337
                           ((None, [None, root_id]), root_id, root_id),
1338
                           ((None, [None, u'a']), u'a', u'a'),
1339
                           ((None, [None, False]), False, False)),
1340
                         ], entries)
1341
3514.4.15 by John Arbash Meinel
Handle when OTHER doesn't have the entry.
1342
    def test_not_in_other(self):
1343
        builder = self.get_builder()
1344
        builder.build_snapshot('A-id', None,
1345
            [('add', (u'', 'a-root-id', 'directory', None)),
1346
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1347
        builder.build_snapshot('B-id', ['A-id'], [])
1348
        builder.build_snapshot('C-id', ['A-id'], [])
1349
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
1350
            [('unversion', 'a-id')])
1351
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1352
        merge_obj = self.make_merge_obj(builder, 'E-id')
1353
1354
        entries = list(merge_obj._entries_lca())
1355
        root_id = 'a-root-id'
1356
        self.assertEqual([('a-id', True,
1357
                           ((root_id, [root_id, root_id]), None, root_id),
1358
                           ((u'a', [u'a', u'a']), None, u'a'),
1359
                           ((False, [False, False]), None, False)),
1360
                         ], entries)
1361
3514.4.16 by John Arbash Meinel
another test for only in OTHER
1362
    def test_only_in_other(self):
1363
        builder = self.get_builder()
1364
        builder.build_snapshot('A-id', None,
1365
            [('add', (u'', 'a-root-id', 'directory', None))])
1366
        builder.build_snapshot('B-id', ['A-id'], [])
1367
        builder.build_snapshot('C-id', ['A-id'], [])
1368
        builder.build_snapshot('E-id', ['C-id', 'B-id'],
1369
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))])
1370
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
1371
        merge_obj = self.make_merge_obj(builder, 'E-id')
1372
1373
        entries = list(merge_obj._entries_lca())
1374
        root_id = 'a-root-id'
1375
        self.assertEqual([('a-id', True,
1376
                           ((None, [None, None]), root_id, None),
1377
                           ((None, [None, None]), u'a', None),
1378
                           ((None, [None, None]), False, None)),
1379
                         ], entries)
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1380
    # TODO: cases to test
1381
    #       simple criss-cross LCAS identical, BASE different
1382
    #       x-x changed from BASE but identical for all LCAs and tips
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1383
    #               should be possible with the same trick of 'not-in-base'
3514.4.16 by John Arbash Meinel
another test for only in OTHER
1384
    #               using a double criss-cross
1385
    #       x-x Only renamed, no content or kind change
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1386
    #       x-x LCAs differ, one in ancestry of other for a given file
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1387
    #       x-x file missing in LCA
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1388
    #       x-x Reverted back to BASE text