/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,
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
27
    transform,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
28
    versionedfile,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
29
    )
974.1.56 by aaron.bentley at utoronto
Added merge test
30
from bzrlib.branch import Branch
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
31
from bzrlib.conflicts import ConflictList, TextConflict
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
32
from bzrlib.errors import UnrelatedBranches, NoCommits, BzrCommandError
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
33
from bzrlib.merge import transform_tree, merge_inner, _PlanMerge
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
34
from bzrlib.osutils import pathjoin, file_kind
1534.4.28 by Robert Collins
first cut at merge from integration.
35
from bzrlib.revision import common_ancestor
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")
109
        last = wt1.branch.last_revision()
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
110
        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
111
112
    def test_create_rename(self):
113
        """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.
114
        tree =self.make_branch_and_tree('.')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
115
        file('name1', 'wb').write('Hello')
116
        tree.add('name1')
117
        tree.commit(message="hello")
118
        tree.rename_one('name1', 'name2')
119
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
120
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
121
122
    def test_layered_rename(self):
123
        """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.
124
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
125
        os.mkdir('dirname1')
126
        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 \
127
        filename = pathjoin('dirname1', 'name1')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
128
        file(filename, 'wb').write('Hello')
129
        tree.add(filename)
130
        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 \
131
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
132
        tree.rename_one(filename, filename2)
133
        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.
134
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
135
136
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
137
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
138
        tree_a =self.make_branch_and_tree('a')
139
        tree_a.commit(message="hello")
140
        dir_b = tree_a.bzrdir.sprout('b')
141
        tree_b = dir_b.open_workingtree()
3146.4.4 by Aaron Bentley
Add write lock, so merge_inner works properly
142
        tree_b.lock_write()
143
        self.addCleanup(tree_b.unlock)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
144
        tree_a.commit(message="hello again")
145
        log = StringIO()
146
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
147
                    this_tree=tree_b, ignore_zero=True)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
148
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
149
        self.failUnless('All changes applied successfully.\n' not in log)
2796.1.3 by Aaron Bentley
update new test case
150
        tree_b.revert()
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
151
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(), 
152
                    this_tree=tree_b, ignore_zero=False)
1927.3.1 by Carl Friedrich Bolz
Throw away on-disk logfile when possible.
153
        log = self._get_log(keep_log_file=True)
1551.4.1 by Aaron Bentley
Workaround for silly _get_log behaviour in test
154
        self.failUnless('All changes applied successfully.\n' in log)
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
155
156
    def test_merge_inner_conflicts(self):
157
        tree_a = self.make_branch_and_tree('a')
158
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
159
        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.
160
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
161
162
    def test_rmdir_conflict(self):
163
        tree_a = self.make_branch_and_tree('a')
164
        self.build_tree(['a/b/'])
165
        tree_a.add('b', 'b-id')
166
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
167
        # basis_tree() is only guaranteed to be valid as long as it is actually
168
        # the basis tree. This mutates the tree after grabbing basis, so go to
169
        # the repository.
170
        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
171
        tree_z = tree_a.bzrdir.sprout('z').open_workingtree()
172
        self.build_tree(['a/b/c'])
173
        tree_a.add('b/c')
174
        tree_a.commit('added c')
175
        os.rmdir('z/b')
176
        tree_z.commit('removed b')
177
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
178
        self.assertEqual([
179
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
180
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
181
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
182
        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
183
                    this_tree=tree_a)
184
        self.assertEqual([
185
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
186
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
187
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
188
2100.3.29 by Aaron Bentley
Get merge working initially
189
    def test_nested_merge(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
190
        tree = self.make_branch_and_tree('tree',
191
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
192
        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.
193
            format='dirstate-with-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
194
        sub_tree.set_root_id('sub-tree-root')
195
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
196
        sub_tree.add('file')
197
        sub_tree.commit('foo')
198
        tree.add_reference(sub_tree)
199
        tree.commit('set text to 1')
200
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
201
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
202
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
203
        # and merge the changes from the diverged subtree into the containing
204
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
205
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
206
        tree.merge_from_branch(tree2.branch)
207
        self.assertFileEqual('text2', 'tree/sub-tree/file')
208
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
209
    def test_merge_with_missing(self):
210
        tree_a = self.make_branch_and_tree('tree_a')
211
        self.build_tree_contents([('tree_a/file', 'content_1')])
212
        tree_a.add('file')
213
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
214
        # basis_tree() is only guaranteed to be valid as long as it is actually
215
        # the basis tree. This mutates the tree after grabbing basis, so go to
216
        # the repository.
217
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
218
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
219
        self.build_tree_contents([('tree_a/file', 'content_2')])
220
        tree_a.commit('commit other')
221
        other_tree = tree_a.basis_tree()
222
        os.unlink('tree_b/file')
223
        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
224
225
    def test_merge_kind_change(self):
226
        tree_a = self.make_branch_and_tree('tree_a')
227
        self.build_tree_contents([('tree_a/file', 'content_1')])
228
        tree_a.add('file', 'file-id')
229
        tree_a.commit('added file')
230
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
231
        os.unlink('tree_a/file')
232
        self.build_tree(['tree_a/file/'])
233
        tree_a.commit('changed file to directory')
234
        tree_b.merge_from_branch(tree_a.branch)
235
        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'
236
        tree_b.revert()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
237
        self.assertEqual('file', file_kind('tree_b/file'))
238
        self.build_tree_contents([('tree_b/file', 'content_2')])
239
        tree_b.commit('content change')
240
        tree_b.merge_from_branch(tree_a.branch)
241
        self.assertEqual(tree_b.conflicts(),
242
                         [conflicts.ContentsConflict('file',
243
                          file_id='file-id')])
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
244
    
245
    def test_merge_type_registry(self):
246
        merge_type_option = option.Option.OPTIONS['merge-type']
247
        self.assertFalse('merge4' in [x[0] for x in 
248
                        merge_type_option.iter_switches()])
249
        registry = _mod_merge.get_merge_type_registry()
250
        registry.register_lazy('merge4', 'bzrlib.merge', 'Merge4Merger',
251
                               'time-travelling merge')
252
        self.assertTrue('merge4' in [x[0] for x in 
253
                        merge_type_option.iter_switches()])
254
        registry.remove('merge4')
255
        self.assertFalse('merge4' in [x[0] for x in 
256
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
257
1551.16.3 by Aaron Bentley
Rename test case
258
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
259
        tree_a = self.make_branch_and_tree('A')
260
        tree_a.lock_write()
261
        self.addCleanup(tree_a.unlock)
262
        self.build_tree(['A/a'])
263
        tree_a.add('a')
264
        tree_a.commit('1', rev_id='rev-1')
265
        tree_a.flush()
266
        tree_a.rename_one('a', 'b')
267
        tree_a.commit('2')
268
        bzrdir_b = tree_a.bzrdir.sprout('B', revision_id='rev-1')
269
        tree_b = bzrdir_b.open_workingtree()
270
        tree_b.lock_write()
271
        self.addCleanup(tree_b.unlock)
272
        os.unlink('B/a')
273
        tree_b.commit('3')
274
        try:
275
            tree_b.merge_from_branch(tree_a.branch)
276
        except AttributeError:
277
            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()
278
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.
279
    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()
280
        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.
281
        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()
282
        tree_a.add(['file_1'])
283
        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.
284
        tree_a.add(['file_2'])
285
        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()
286
        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.
287
        tree_b.rename_one('file_1', 'renamed')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
288
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
289
                                                    progress.DummyProgress())
290
        merger.merge_type = _mod_merge.Merge3Merger
291
        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.
292
        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
293
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
294
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis_weave(self):
295
        tree_a = self.make_branch_and_tree('a')
296
        self.build_tree(['a/file_1', 'a/file_2'])
297
        tree_a.add(['file_1'])
298
        tree_a.commit('commit 1')
299
        tree_a.add(['file_2'])
300
        tree_a.commit('commit 2')
301
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
302
        tree_b.rename_one('file_1', 'renamed')
303
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b,
304
                                                    progress.DummyProgress())
305
        merger.merge_type = _mod_merge.WeaveMerger
306
        merger.do_merge()
307
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
308
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
309
    def prepare_cherrypick(self):
3062.2.13 by Aaron Bentley
Update prepare_cherrypick docstring
310
        """Prepare a pair of trees for cherrypicking tests.
311
312
        Both trees have a file, 'file'.
313
        rev1 sets content to 'a'.
314
        rev2b adds 'b'.
315
        rev3b adds 'c'.
316
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
317
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
318
        'c', but not 'b'.
319
        """
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
320
        this_tree = self.make_branch_and_tree('this')
321
        self.build_tree_contents([('this/file', "a\n")])
322
        this_tree.add('file')
323
        this_tree.commit('rev1')
324
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
325
        self.build_tree_contents([('other/file', "a\nb\n")])
326
        other_tree.commit('rev2b', rev_id='rev2b')
327
        self.build_tree_contents([('other/file', "c\na\nb\n")])
328
        other_tree.commit('rev3b', rev_id='rev3b')
329
        this_tree.lock_write()
330
        self.addCleanup(this_tree.unlock)
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
331
        return this_tree, other_tree
332
333
    def test_weave_cherrypick(self):
334
        this_tree, other_tree = self.prepare_cherrypick()
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
335
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
336
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
337
        merger.merge_type = _mod_merge.WeaveMerger
338
        merger.do_merge()
339
        self.assertFileEqual('c\na\n', 'this/file')
340
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
341
    def test_weave_cannot_reverse_cherrypick(self):
342
        this_tree, other_tree = self.prepare_cherrypick()
343
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
344
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
345
        merger.merge_type = _mod_merge.WeaveMerger
346
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
347
348
    def test_merge3_can_reverse_cherrypick(self):
349
        this_tree, other_tree = self.prepare_cherrypick()
350
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
351
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
352
        merger.merge_type = _mod_merge.Merge3Merger
353
        merger.do_merge()
354
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
355
    def test_make_merger(self):
356
        this_tree = self.make_branch_and_tree('this')
357
        this_tree.commit('rev1', rev_id='rev1')
358
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
359
        this_tree.commit('rev2', rev_id='rev2a')
360
        other_tree.commit('rev2', rev_id='rev2b')
361
        this_tree.lock_write()
362
        self.addCleanup(this_tree.unlock)
363
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress,
364
            this_tree, 'rev2b', other_branch=other_tree.branch)
365
        merger.merge_type = _mod_merge.Merge3Merger
366
        tree_merger = merger.make_merger()
367
        self.assertIs(_mod_merge.Merge3Merger, tree_merger.__class__)
368
        self.assertEqual('rev2b', tree_merger.other_tree.get_revision_id())
369
        self.assertEqual('rev1', tree_merger.base_tree.get_revision_id())
370
371
    def test_make_preview_transform(self):
372
        this_tree = self.make_branch_and_tree('this')
373
        self.build_tree_contents([('this/file', '1\n')])
374
        this_tree.add('file', 'file-id')
375
        this_tree.commit('rev1', rev_id='rev1')
376
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
377
        self.build_tree_contents([('this/file', '1\n2a\n')])
378
        this_tree.commit('rev2', rev_id='rev2a')
379
        self.build_tree_contents([('other/file', '2b\n1\n')])
380
        other_tree.commit('rev2', rev_id='rev2b')
381
        this_tree.lock_write()
382
        self.addCleanup(this_tree.unlock)
383
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
384
            this_tree, 'rev2b', other_branch=other_tree.branch)
385
        merger.merge_type = _mod_merge.Merge3Merger
386
        tree_merger = merger.make_merger()
387
        tt = tree_merger.make_preview_transform()
388
        preview_tree = tt.get_preview_tree()
389
        tree_file = this_tree.get_file('file-id')
390
        try:
391
            self.assertEqual('1\n2a\n', tree_file.read())
392
        finally:
393
            tree_file.close()
394
        preview_file = preview_tree.get_file('file-id')
395
        try:
396
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
397
        finally:
398
            preview_file.close()
399
3008.1.22 by Aaron Bentley
Get do_merge under test
400
    def test_do_merge(self):
401
        this_tree = self.make_branch_and_tree('this')
402
        self.build_tree_contents([('this/file', '1\n')])
403
        this_tree.add('file', 'file-id')
404
        this_tree.commit('rev1', rev_id='rev1')
405
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
406
        self.build_tree_contents([('this/file', '1\n2a\n')])
407
        this_tree.commit('rev2', rev_id='rev2a')
408
        self.build_tree_contents([('other/file', '2b\n1\n')])
409
        other_tree.commit('rev2', rev_id='rev2b')
410
        this_tree.lock_write()
411
        self.addCleanup(this_tree.unlock)
412
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
413
            this_tree, 'rev2b', other_branch=other_tree.branch)
414
        merger.merge_type = _mod_merge.Merge3Merger
415
        tree_merger = merger.make_merger()
416
        tt = tree_merger.do_merge()
417
        tree_file = this_tree.get_file('file-id')
418
        try:
419
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
420
        finally:
421
            tree_file.close()
422
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
423
424
class TestPlanMerge(TestCaseWithMemoryTransport):
425
426
    def setUp(self):
427
        TestCaseWithMemoryTransport.setUp(self)
428
        self.vf = knit.KnitVersionedFile('root', self.get_transport(),
429
                                         create=True)
430
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
431
                                                                   [self.vf])
432
433
    def add_version(self, version_id, parents, text):
434
        self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
435
436
    def add_uncommitted_version(self, version_id, parents, text):
437
        self.plan_merge_vf.add_lines(version_id, parents,
438
                                     [c+'\n' for c in text])
439
440
    def setup_plan_merge(self):
441
        self.add_version('A', [], 'abc')
442
        self.add_version('B', ['A'], 'acehg')
443
        self.add_version('C', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
444
        return _PlanMerge('B', 'C', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
445
446
    def setup_plan_merge_uncommitted(self):
447
        self.add_version('A', [], 'abc')
448
        self.add_uncommitted_version('B:', ['A'], 'acehg')
449
        self.add_uncommitted_version('C:', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
450
        return _PlanMerge('B:', 'C:', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
451
452
    def test_unique_lines(self):
453
        plan = self.setup_plan_merge()
454
        self.assertEqual(plan._unique_lines(
455
            plan._get_matching_blocks('B', 'C')),
456
            ([1, 2, 3], [0, 2]))
457
458
    def test_find_new(self):
459
        plan = self.setup_plan_merge()
460
        self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
461
        self.assertEqual(set([0, 3]), plan._find_new('C'))
462
463
    def test_find_new2(self):
464
        self.add_version('A', [], 'abc')
465
        self.add_version('B', ['A'], 'abcde')
466
        self.add_version('C', ['A'], 'abcefg')
467
        self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
468
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
469
        self.assertEqual(set([5, 6]), my_plan._find_new('D'))
470
        self.assertEqual(set(), my_plan._find_new('A'))
471
472
    def test_find_new_no_ancestors(self):
473
        self.add_version('A', [], 'abc')
474
        self.add_version('B', [], 'xyz')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
475
        my_plan = _PlanMerge('A', 'B', self.vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
476
        self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
477
478
    def test_plan_merge(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
479
        self.setup_plan_merge()
480
        plan = self.plan_merge_vf.plan_merge('B', 'C')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
481
        self.assertEqual([
482
                          ('new-b', 'f\n'),
483
                          ('unchanged', 'a\n'),
484
                          ('killed-b', 'c\n'),
485
                          ('new-a', 'e\n'),
486
                          ('new-a', 'h\n'),
487
                          ('killed-a', 'b\n'),
488
                          ('unchanged', 'g\n')],
489
                         list(plan))
490
491
    def test_plan_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
492
        self.setup_plan_merge_uncommitted()
493
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
494
        self.assertEqual([
495
                          ('new-b', 'f\n'),
496
                          ('unchanged', 'a\n'),
497
                          ('killed-b', 'c\n'),
498
                          ('new-a', 'e\n'),
499
                          ('new-a', 'h\n'),
500
                          ('killed-a', 'b\n'),
501
                          ('unchanged', 'g\n')],
502
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
503
504
    def test_subtract_plans(self):
505
        old_plan = [
506
        ('unchanged', 'a\n'),
507
        ('new-a', 'b\n'),
508
        ('killed-a', 'c\n'),
509
        ('new-b', 'd\n'),
510
        ('new-b', 'e\n'),
511
        ('killed-b', 'f\n'),
512
        ('killed-b', 'g\n'),
513
        ]
514
        new_plan = [
515
        ('unchanged', 'a\n'),
516
        ('new-a', 'b\n'),
517
        ('killed-a', 'c\n'),
518
        ('new-b', 'd\n'),
519
        ('new-b', 'h\n'),
520
        ('killed-b', 'f\n'),
521
        ('killed-b', 'i\n'),
522
        ]
523
        subtracted_plan = [
524
        ('unchanged', 'a\n'),
525
        ('new-a', 'b\n'),
526
        ('killed-a', 'c\n'),
527
        ('new-b', 'h\n'),
528
        ('unchanged', 'f\n'),
529
        ('killed-b', 'i\n'),
530
        ]
531
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
532
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
533
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
534
    def setup_merge_with_base(self):
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
535
        self.add_version('COMMON', [], 'abc')
536
        self.add_version('THIS', ['COMMON'], 'abcd')
537
        self.add_version('BASE', ['COMMON'], 'eabc')
538
        self.add_version('OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
539
540
    def test_plan_merge_with_base(self):
541
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
542
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
543
        self.assertEqual([('unchanged', 'a\n'),
544
                          ('new-b', 'f\n'),
545
                          ('unchanged', 'b\n'),
546
                          ('killed-b', 'c\n'),
547
                          ('new-a', 'd\n')
548
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
549
550
    def test_plan_lca_merge(self):
551
        self.setup_plan_merge()
552
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
553
        self.assertEqual([
554
                          ('new-b', 'f\n'),
555
                          ('unchanged', 'a\n'),
556
                          ('killed-b', 'c\n'),
557
                          ('new-a', 'e\n'),
558
                          ('new-a', 'h\n'),
559
                          ('killed-a', 'b\n'),
560
                          ('unchanged', 'g\n')],
561
                         list(plan))
562
563
    def test_plan_lca_merge_uncommitted_files(self):
564
        self.setup_plan_merge_uncommitted()
565
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
566
        self.assertEqual([
567
                          ('new-b', 'f\n'),
568
                          ('unchanged', 'a\n'),
569
                          ('killed-b', 'c\n'),
570
                          ('new-a', 'e\n'),
571
                          ('new-a', 'h\n'),
572
                          ('killed-a', 'b\n'),
573
                          ('unchanged', 'g\n')],
574
                         list(plan))
575
576
    def test_plan_lca_merge_with_base(self):
577
        self.setup_merge_with_base()
578
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
579
        self.assertEqual([('unchanged', 'a\n'),
580
                          ('new-b', 'f\n'),
581
                          ('unchanged', 'b\n'),
582
                          ('killed-b', 'c\n'),
583
                          ('new-a', 'd\n')
584
                         ], list(plan))
585
586
    def test_plan_lca_merge_with_criss_cross(self):
587
        self.add_version('ROOT', [], 'abc')
588
        # each side makes a change
589
        self.add_version('REV1', ['ROOT'], 'abcd')
590
        self.add_version('REV2', ['ROOT'], 'abce')
591
        # both sides merge, discarding others' changes
592
        self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
593
        self.add_version('LCA2', ['REV1', 'REV2'], 'abce')
594
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
595
        self.assertEqual([('unchanged', 'a\n'),
596
                          ('unchanged', 'b\n'),
597
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
598
                          ('conflicted-a', 'd\n'),
599
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
600
                         ], list(plan))