/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,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
24
    merge as _mod_merge,
25
    option,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
26
    progress,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
27
    versionedfile,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
28
    )
974.1.56 by aaron.bentley at utoronto
Added merge test
29
from bzrlib.branch import Branch
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
30
from bzrlib.conflicts import ConflictList, TextConflict
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
31
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
32
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
33
from bzrlib.osutils import pathjoin, file_kind
1534.4.28 by Robert Collins
first cut at merge from integration.
34
from bzrlib.revision import common_ancestor
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
35
from bzrlib.tests import TestCaseWithTransport, TestCaseWithMemoryTransport
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
36
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.
37
from bzrlib.workingtree import WorkingTree
38
39
40
class TestMerge(TestCaseWithTransport):
974.1.56 by aaron.bentley at utoronto
Added merge test
41
    """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.
42
974.1.56 by aaron.bentley at utoronto
Added merge test
43
    def test_pending(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
44
        wt = self.make_branch_and_tree('.')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
45
        rev_a = wt.commit("lala!")
46
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
47
        self.assertRaises(errors.PointlessMerge, wt.merge_from_branch,
48
                          wt.branch)
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
49
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
50
        return wt
974.1.80 by Aaron Bentley
Improved merge error handling and testing
51
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
52
    def test_undo(self):
53
        wt = self.make_branch_and_tree('.')
54
        wt.commit("lala!")
55
        wt.commit("haha!")
56
        wt.commit("blabla!")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
57
        wt.merge_from_branch(wt.branch, wt.branch.get_rev_id(2),
58
                             wt.branch.get_rev_id(1))
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
59
974.1.80 by Aaron Bentley
Improved merge error handling and testing
60
    def test_nocommits(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
61
        wt = self.test_pending()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
62
        wt2 = self.make_branch_and_tree('branch2')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
63
        self.assertRaises(NoCommits, wt.merge_from_branch, wt2.branch)
64
        return wt, wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
65
66
    def test_unrelated(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
67
        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.
68
        wt2.commit("blah")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
69
        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.
70
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
71
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
72
    def test_merge_one_file(self):
73
        """Do a partial merge of a tree which should not affect tree parents."""
1645.1.1 by Aaron Bentley
Implement single-file merge
74
        wt1 = self.make_branch_and_tree('branch1')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
75
        tip = wt1.commit('empty commit')
1645.1.1 by Aaron Bentley
Implement single-file merge
76
        wt2 = self.make_branch_and_tree('branch2')
77
        wt2.pull(wt1.branch)
78
        file('branch1/foo', 'wb').write('foo')
79
        file('branch1/bar', 'wb').write('bar')
80
        wt1.add('foo')
81
        wt1.add('bar')
82
        wt1.commit('add foobar')
83
        os.chdir('branch2')
2530.3.1 by Martin Pool
Cleanup old variations on run_bzr in the test suite
84
        self.run_bzr('merge ../branch1/baz', retcode=3)
85
        self.run_bzr('merge ../branch1/foo')
1645.1.1 by Aaron Bentley
Implement single-file merge
86
        self.failUnlessExists('foo')
87
        self.failIfExists('bar')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
88
        wt2 = WorkingTree.open('.') # opens branch2
89
        self.assertEqual([tip], wt2.get_parent_ids())
1908.6.9 by Robert Collins
Fix status to not use pending_merges.
90
        
974.1.88 by Aaron Bentley
Set a pending_merge if the merge base is forced to revno 0
91
    def test_pending_with_null(self):
1551.8.25 by Aaron Bentley
Fix deprecated use of pending_merges
92
        """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.
93
        wt2 = self.test_unrelated()
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
94
        wt1 = WorkingTree.open('.')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
95
        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.
96
        br1.fetch(wt2.branch)
1390 by Robert Collins
pair programming worx... merge integration and weave
97
        # merge all of branch 2 into branch 1 even though they 
98
        # are not related.
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
99
        wt1.merge_from_branch(wt2.branch, wt2.last_revision(), 'null:')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
100
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
101
            wt1.get_parent_ids())
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
102
        return (wt1, wt2.branch)
974.1.89 by Aaron Bentley
Fixed merging with multiple roots, by using null as graph root.
103
104
    def test_two_roots(self):
105
        """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.
106
        wt1, br2 = self.test_pending_with_null()
107
        wt1.commit("blah")
108
        last = wt1.branch.last_revision()
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
109
        self.assertEqual(common_ancestor(last, last, wt1.branch.repository), last)
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
110
111
    def test_create_rename(self):
112
        """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.
113
        tree =self.make_branch_and_tree('.')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
114
        file('name1', 'wb').write('Hello')
115
        tree.add('name1')
116
        tree.commit(message="hello")
117
        tree.rename_one('name1', 'name2')
118
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
119
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
120
121
    def test_layered_rename(self):
122
        """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.
123
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
124
        os.mkdir('dirname1')
125
        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 \
126
        filename = pathjoin('dirname1', 'name1')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
127
        file(filename, 'wb').write('Hello')
128
        tree.add(filename)
129
        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 \
130
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
131
        tree.rename_one(filename, filename2)
132
        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.
133
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
134
135
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
136
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
137
        tree_a =self.make_branch_and_tree('a')
138
        tree_a.commit(message="hello")
139
        dir_b = tree_a.bzrdir.sprout('b')
140
        tree_b = dir_b.open_workingtree()
3146.4.4 by Aaron Bentley
Add write lock, so merge_inner works properly
141
        tree_b.lock_write()
142
        self.addCleanup(tree_b.unlock)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
143
        tree_a.commit(message="hello again")
144
        log = StringIO()
145
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
146
                    this_tree=tree_b, ignore_zero=True)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
147
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
148
        self.failUnless('All changes applied successfully.\n' not in log)
2796.1.3 by Aaron Bentley
update new test case
149
        tree_b.revert()
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
150
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
151
                    this_tree=tree_b, ignore_zero=False)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
152
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
153
        self.failUnless('All changes applied successfully.\n' in log)
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
154
155
    def test_merge_inner_conflicts(self):
156
        tree_a = self.make_branch_and_tree('a')
157
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
158
        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.
159
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
160
161
    def test_rmdir_conflict(self):
162
        tree_a = self.make_branch_and_tree('a')
163
        self.build_tree(['a/b/'])
164
        tree_a.add('b', 'b-id')
165
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
166
        # basis_tree() is only guaranteed to be valid as long as it is actually
167
        # the basis tree. This mutates the tree after grabbing basis, so go to
168
        # the repository.
169
        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
170
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
171
        self.build_tree(['a/b/c'])
172
        tree_a.add('b/c')
173
        tree_a.commit('added c')
174
        os.rmdir('z/b')
175
        tree_z.commit('removed b')
176
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
177
        self.assertEqual([
178
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
179
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
180
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
181
        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
182
                    this_tree=tree_a)
183
        self.assertEqual([
184
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
185
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
186
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
187
2100.3.29 by Aaron Bentley
Get merge working initially
188
    def test_nested_merge(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
189
        tree = self.make_branch_and_tree('tree',
190
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
191
        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.
192
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
193
        sub_tree.set_root_id('sub-tree-root')
194
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
195
        sub_tree.add('file')
196
        sub_tree.commit('foo')
197
        tree.add_reference(sub_tree)
198
        tree.commit('set text to 1')
199
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
200
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
201
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
202
        # and merge the changes from the diverged subtree into the containing
203
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
204
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
205
        tree.merge_from_branch(tree2.branch)
206
        self.assertFileEqual('text2', 'tree/sub-tree/file')
207
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
208
    def test_merge_with_missing(self):
209
        tree_a = self.make_branch_and_tree('tree_a')
210
        self.build_tree_contents([('tree_a/file', 'content_1')])
211
        tree_a.add('file')
212
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
213
        # basis_tree() is only guaranteed to be valid as long as it is actually
214
        # the basis tree. This mutates the tree after grabbing basis, so go to
215
        # the repository.
216
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
217
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
218
        self.build_tree_contents([('tree_a/file', 'content_2')])
219
        tree_a.commit('commit other')
220
        other_tree = tree_a.basis_tree()
221
        os.unlink('tree_b/file')
222
        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
223
224
    def test_merge_kind_change(self):
225
        tree_a = self.make_branch_and_tree('tree_a')
226
        self.build_tree_contents([('tree_a/file', 'content_1')])
227
        tree_a.add('file', 'file-id')
228
        tree_a.commit('added file')
229
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
230
        os.unlink('tree_a/file')
231
        self.build_tree(['tree_a/file/'])
232
        tree_a.commit('changed file to directory')
233
        tree_b.merge_from_branch(tree_a.branch)
234
        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'
235
        tree_b.revert()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
236
        self.assertEqual('file', file_kind('tree_b/file'))
237
        self.build_tree_contents([('tree_b/file', 'content_2')])
238
        tree_b.commit('content change')
239
        tree_b.merge_from_branch(tree_a.branch)
240
        self.assertEqual(tree_b.conflicts(),
241
                         [conflicts.ContentsConflict('file',
242
                          file_id='file-id')])
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
243
    
244
    def test_merge_type_registry(self):
245
        merge_type_option = option.Option.OPTIONS['merge-type']
246
        self.assertFalse('merge4' in [x[0] for x in 
247
                        merge_type_option.iter_switches()])
248
        registry = _mod_merge.get_merge_type_registry()
249
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
250
                               'time-travelling merge')
251
        self.assertTrue('merge4' in [x[0] for x in 
252
                        merge_type_option.iter_switches()])
253
        registry.remove('merge4')
254
        self.assertFalse('merge4' in [x[0] for x in 
255
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
256
1551.16.3 by Aaron Bentley
Rename test case
257
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
258
        tree_a = self.make_branch_and_tree('A')
259
        tree_a.lock_write()
260
        self.addCleanup(tree_a.unlock)
261
        self.build_tree(['A/a'])
262
        tree_a.add('a')
263
        tree_a.commit('1', rev_id='rev-1')
264
        tree_a.flush()
265
        tree_a.rename_one('a', 'b')
266
        tree_a.commit('2')
267
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
268
        tree_b = bzrdir_b.open_workingtree()
269
        tree_b.lock_write()
270
        self.addCleanup(tree_b.unlock)
271
        os.unlink('B/a')
272
        tree_b.commit('3')
273
        try:
274
            tree_b.merge_from_branch(tree_a.branch)
275
        except AttributeError:
276
            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()
277
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.
278
    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()
279
        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.
280
        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()
281
        tree_a.add(['file_1'])
282
        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.
283
        tree_a.add(['file_2'])
284
        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()
285
        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.
286
        tree_b.rename_one('file_1', 'renamed')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
287
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
288
                                                    progress.DummyProgress())
289
        merger.merge_type = _mod_merge.Merge3Merger
290
        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.
291
        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
292
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
293
    def prepare_cherrypick(self):
3062.2.13 by Aaron Bentley
Update prepare_cherrypick docstring
294
        """Prepare a pair of trees for cherrypicking tests.
295
296
        Both trees have a file, 'file'.
297
        rev1 sets content to 'a'.
298
        rev2b adds 'b'.
299
        rev3b adds 'c'.
300
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
301
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
302
        'c', but not 'b'.
303
        """
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
304
        this_tree = self.make_branch_and_tree('this')
305
        self.build_tree_contents([('this/file', "a\n")])
306
        this_tree.add('file')
307
        this_tree.commit('rev1')
308
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
309
        self.build_tree_contents([('other/file', "a\nb\n")])
310
        other_tree.commit('rev2b', rev_id='rev2b')
311
        self.build_tree_contents([('other/file', "c\na\nb\n")])
312
        other_tree.commit('rev3b', rev_id='rev3b')
313
        this_tree.lock_write()
314
        self.addCleanup(this_tree.unlock)
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
315
        return this_tree, other_tree
316
317
    def test_weave_cherrypick(self):
318
        this_tree, other_tree = self.prepare_cherrypick()
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
319
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
320
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
321
        merger.merge_type = _mod_merge.WeaveMerger
322
        merger.do_merge()
323
        self.assertFileEqual('c\na\n', 'this/file')
324
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
325
    def test_weave_cannot_reverse_cherrypick(self):
326
        this_tree, other_tree = self.prepare_cherrypick()
327
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
328
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
329
        merger.merge_type = _mod_merge.WeaveMerger
330
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
331
332
    def test_merge3_can_reverse_cherrypick(self):
333
        this_tree, other_tree = self.prepare_cherrypick()
334
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
335
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
336
        merger.merge_type = _mod_merge.Merge3Merger
337
        merger.do_merge()
338
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
339
340
class TestPlanMerge(TestCaseWithMemoryTransport):
341
342
    def setUp(self):
343
        TestCaseWithMemoryTransport.setUp(self)
344
        self.vf = knit.KnitVersionedFile('root', self.get_transport(),
345
                                         create=True)
346
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
347
                                                                   [self.vf])
348
349
    def add_version(self, version_id, parents, text):
350
        self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
351
352
    def add_uncommitted_version(self, version_id, parents, text):
353
        self.plan_merge_vf.add_lines(version_id, parents,
354
                                     [c+'\n' for c in text])
355
356
    def setup_plan_merge(self):
357
        self.add_version('A', [], 'abc')
358
        self.add_version('B', ['A'], 'acehg')
359
        self.add_version('C', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
360
        return _PlanMerge('B', 'C', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
361
362
    def setup_plan_merge_uncommitted(self):
363
        self.add_version('A', [], 'abc')
364
        self.add_uncommitted_version('B:', ['A'], 'acehg')
365
        self.add_uncommitted_version('C:', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
366
        return _PlanMerge('B:', 'C:', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
367
368
    def test_unique_lines(self):
369
        plan = self.setup_plan_merge()
370
        self.assertEqual(plan._unique_lines(
371
            plan._get_matching_blocks('B', 'C')),
372
            ([1, 2, 3], [0, 2]))
373
374
    def test_find_new(self):
375
        plan = self.setup_plan_merge()
376
        self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
377
        self.assertEqual(set([0, 3]), plan._find_new('C'))
378
379
    def test_find_new2(self):
380
        self.add_version('A', [], 'abc')
381
        self.add_version('B', ['A'], 'abcde')
382
        self.add_version('C', ['A'], 'abcefg')
383
        self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
384
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
385
        self.assertEqual(set([5, 6]), my_plan._find_new('D'))
386
        self.assertEqual(set(), my_plan._find_new('A'))
387
388
    def test_find_new_no_ancestors(self):
389
        self.add_version('A', [], 'abc')
390
        self.add_version('B', [], 'xyz')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
391
        my_plan = _PlanMerge('A', 'B', self.vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
392
        self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
393
394
    def test_plan_merge(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
395
        self.setup_plan_merge()
396
        plan = self.plan_merge_vf.plan_merge('B', 'C')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
397
        self.assertEqual([
398
                          ('new-b', 'f\n'),
399
                          ('unchanged', 'a\n'),
400
                          ('killed-b', 'c\n'),
401
                          ('new-a', 'e\n'),
402
                          ('new-a', 'h\n'),
403
                          ('killed-a', 'b\n'),
404
                          ('unchanged', 'g\n')],
405
                         list(plan))
406
407
    def test_plan_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
408
        self.setup_plan_merge_uncommitted()
409
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
410
        self.assertEqual([
411
                          ('new-b', 'f\n'),
412
                          ('unchanged', 'a\n'),
413
                          ('killed-b', 'c\n'),
414
                          ('new-a', 'e\n'),
415
                          ('new-a', 'h\n'),
416
                          ('killed-a', 'b\n'),
417
                          ('unchanged', 'g\n')],
418
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
419
420
    def test_subtract_plans(self):
421
        old_plan = [
422
        ('unchanged', 'a\n'),
423
        ('new-a', 'b\n'),
424
        ('killed-a', 'c\n'),
425
        ('new-b', 'd\n'),
426
        ('new-b', 'e\n'),
427
        ('killed-b', 'f\n'),
428
        ('killed-b', 'g\n'),
429
        ]
430
        new_plan = [
431
        ('unchanged', 'a\n'),
432
        ('new-a', 'b\n'),
433
        ('killed-a', 'c\n'),
434
        ('new-b', 'd\n'),
435
        ('new-b', 'h\n'),
436
        ('killed-b', 'f\n'),
437
        ('killed-b', 'i\n'),
438
        ]
439
        subtracted_plan = [
440
        ('unchanged', 'a\n'),
441
        ('new-a', 'b\n'),
442
        ('killed-a', 'c\n'),
443
        ('new-b', 'h\n'),
444
        ('unchanged', 'f\n'),
445
        ('killed-b', 'i\n'),
446
        ]
447
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
448
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
449
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
450
    def setup_merge_with_base(self):
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
451
        self.add_version('COMMON', [], 'abc')
452
        self.add_version('THIS', ['COMMON'], 'abcd')
453
        self.add_version('BASE', ['COMMON'], 'eabc')
454
        self.add_version('OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
455
456
    def test_plan_merge_with_base(self):
457
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
458
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
459
        self.assertEqual([('unchanged', 'a\n'),
460
                          ('new-b', 'f\n'),
461
                          ('unchanged', 'b\n'),
462
                          ('killed-b', 'c\n'),
463
                          ('new-a', 'd\n')
464
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
465
466
    def test_plan_lca_merge(self):
467
        self.setup_plan_merge()
468
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
469
        self.assertEqual([
470
                          ('new-b', 'f\n'),
471
                          ('unchanged', 'a\n'),
472
                          ('killed-b', 'c\n'),
473
                          ('new-a', 'e\n'),
474
                          ('new-a', 'h\n'),
475
                          ('killed-a', 'b\n'),
476
                          ('unchanged', 'g\n')],
477
                         list(plan))
478
479
    def test_plan_lca_merge_uncommitted_files(self):
480
        self.setup_plan_merge_uncommitted()
481
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
482
        self.assertEqual([
483
                          ('new-b', 'f\n'),
484
                          ('unchanged', 'a\n'),
485
                          ('killed-b', 'c\n'),
486
                          ('new-a', 'e\n'),
487
                          ('new-a', 'h\n'),
488
                          ('killed-a', 'b\n'),
489
                          ('unchanged', 'g\n')],
490
                         list(plan))
491
492
    def test_plan_lca_merge_with_base(self):
493
        self.setup_merge_with_base()
494
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
495
        self.assertEqual([('unchanged', 'a\n'),
496
                          ('new-b', 'f\n'),
497
                          ('unchanged', 'b\n'),
498
                          ('killed-b', 'c\n'),
499
                          ('new-a', 'd\n')
500
                         ], list(plan))
501
502
    def test_plan_lca_merge_with_criss_cross(self):
503
        self.add_version('ROOT', [], 'abc')
504
        # each side makes a change
505
        self.add_version('REV1', ['ROOT'], 'abcd')
506
        self.add_version('REV2', ['ROOT'], 'abce')
507
        # both sides merge, discarding others' changes
508
        self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
509
        self.add_version('LCA2', ['REV1', 'REV2'], 'abce')
510
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
511
        self.assertEqual([('unchanged', 'a\n'),
512
                          ('unchanged', 'b\n'),
513
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
514
                          ('conflicted-a', 'd\n'),
515
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
516
                         ], list(plan))