/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()
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
388
        self.addCleanup(tt.finalize)
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
389
        preview_tree = tt.get_preview_tree()
390
        tree_file = this_tree.get_file('file-id')
391
        try:
392
            self.assertEqual('1\n2a\n', tree_file.read())
393
        finally:
394
            tree_file.close()
395
        preview_file = preview_tree.get_file('file-id')
396
        try:
397
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
398
        finally:
399
            preview_file.close()
400
3008.1.22 by Aaron Bentley
Get do_merge under test
401
    def test_do_merge(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.do_merge()
418
        tree_file = this_tree.get_file('file-id')
419
        try:
420
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
421
        finally:
422
            tree_file.close()
423
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
424
425
class TestPlanMerge(TestCaseWithMemoryTransport):
426
427
    def setUp(self):
428
        TestCaseWithMemoryTransport.setUp(self)
429
        self.vf = knit.KnitVersionedFile('root', self.get_transport(),
430
                                         create=True)
431
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root',
432
                                                                   [self.vf])
433
434
    def add_version(self, version_id, parents, text):
435
        self.vf.add_lines(version_id, parents, [c+'\n' for c in text])
436
437
    def add_uncommitted_version(self, version_id, parents, text):
438
        self.plan_merge_vf.add_lines(version_id, parents,
439
                                     [c+'\n' for c in text])
440
441
    def setup_plan_merge(self):
442
        self.add_version('A', [], 'abc')
443
        self.add_version('B', ['A'], 'acehg')
444
        self.add_version('C', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
445
        return _PlanMerge('B', 'C', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
446
447
    def setup_plan_merge_uncommitted(self):
448
        self.add_version('A', [], 'abc')
449
        self.add_uncommitted_version('B:', ['A'], 'acehg')
450
        self.add_uncommitted_version('C:', ['A'], 'fabg')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
451
        return _PlanMerge('B:', 'C:', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
452
453
    def test_unique_lines(self):
454
        plan = self.setup_plan_merge()
455
        self.assertEqual(plan._unique_lines(
456
            plan._get_matching_blocks('B', 'C')),
457
            ([1, 2, 3], [0, 2]))
458
459
    def test_find_new(self):
460
        plan = self.setup_plan_merge()
461
        self.assertEqual(set([2, 3, 4]), plan._find_new('B'))
462
        self.assertEqual(set([0, 3]), plan._find_new('C'))
463
464
    def test_find_new2(self):
465
        self.add_version('A', [], 'abc')
466
        self.add_version('B', ['A'], 'abcde')
467
        self.add_version('C', ['A'], 'abcefg')
468
        self.add_version('D', ['A', 'B', 'C'], 'abcdegh')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
469
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
470
        self.assertEqual(set([5, 6]), my_plan._find_new('D'))
471
        self.assertEqual(set(), my_plan._find_new('A'))
472
473
    def test_find_new_no_ancestors(self):
474
        self.add_version('A', [], 'abc')
475
        self.add_version('B', [], 'xyz')
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
476
        my_plan = _PlanMerge('A', 'B', self.vf)
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
477
        self.assertEqual(set([0, 1, 2]), my_plan._find_new('A'))
478
479
    def test_plan_merge(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
480
        self.setup_plan_merge()
481
        plan = self.plan_merge_vf.plan_merge('B', 'C')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
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_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
493
        self.setup_plan_merge_uncommitted()
494
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
495
        self.assertEqual([
496
                          ('new-b', 'f\n'),
497
                          ('unchanged', 'a\n'),
498
                          ('killed-b', 'c\n'),
499
                          ('new-a', 'e\n'),
500
                          ('new-a', 'h\n'),
501
                          ('killed-a', 'b\n'),
502
                          ('unchanged', 'g\n')],
503
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
504
505
    def test_subtract_plans(self):
506
        old_plan = [
507
        ('unchanged', 'a\n'),
508
        ('new-a', 'b\n'),
509
        ('killed-a', 'c\n'),
510
        ('new-b', 'd\n'),
511
        ('new-b', 'e\n'),
512
        ('killed-b', 'f\n'),
513
        ('killed-b', 'g\n'),
514
        ]
515
        new_plan = [
516
        ('unchanged', 'a\n'),
517
        ('new-a', 'b\n'),
518
        ('killed-a', 'c\n'),
519
        ('new-b', 'd\n'),
520
        ('new-b', 'h\n'),
521
        ('killed-b', 'f\n'),
522
        ('killed-b', 'i\n'),
523
        ]
524
        subtracted_plan = [
525
        ('unchanged', 'a\n'),
526
        ('new-a', 'b\n'),
527
        ('killed-a', 'c\n'),
528
        ('new-b', 'h\n'),
529
        ('unchanged', 'f\n'),
530
        ('killed-b', 'i\n'),
531
        ]
532
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
533
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
534
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
535
    def setup_merge_with_base(self):
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
536
        self.add_version('COMMON', [], 'abc')
537
        self.add_version('THIS', ['COMMON'], 'abcd')
538
        self.add_version('BASE', ['COMMON'], 'eabc')
539
        self.add_version('OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
540
541
    def test_plan_merge_with_base(self):
542
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
543
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
544
        self.assertEqual([('unchanged', 'a\n'),
545
                          ('new-b', 'f\n'),
546
                          ('unchanged', 'b\n'),
547
                          ('killed-b', 'c\n'),
548
                          ('new-a', 'd\n')
549
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
550
551
    def test_plan_lca_merge(self):
552
        self.setup_plan_merge()
553
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
554
        self.assertEqual([
555
                          ('new-b', 'f\n'),
556
                          ('unchanged', 'a\n'),
557
                          ('killed-b', 'c\n'),
558
                          ('new-a', 'e\n'),
559
                          ('new-a', 'h\n'),
560
                          ('killed-a', 'b\n'),
561
                          ('unchanged', 'g\n')],
562
                         list(plan))
563
564
    def test_plan_lca_merge_uncommitted_files(self):
565
        self.setup_plan_merge_uncommitted()
566
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
567
        self.assertEqual([
568
                          ('new-b', 'f\n'),
569
                          ('unchanged', 'a\n'),
570
                          ('killed-b', 'c\n'),
571
                          ('new-a', 'e\n'),
572
                          ('new-a', 'h\n'),
573
                          ('killed-a', 'b\n'),
574
                          ('unchanged', 'g\n')],
575
                         list(plan))
576
577
    def test_plan_lca_merge_with_base(self):
578
        self.setup_merge_with_base()
579
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
580
        self.assertEqual([('unchanged', 'a\n'),
581
                          ('new-b', 'f\n'),
582
                          ('unchanged', 'b\n'),
583
                          ('killed-b', 'c\n'),
584
                          ('new-a', 'd\n')
585
                         ], list(plan))
586
587
    def test_plan_lca_merge_with_criss_cross(self):
588
        self.add_version('ROOT', [], 'abc')
589
        # each side makes a change
590
        self.add_version('REV1', ['ROOT'], 'abcd')
591
        self.add_version('REV2', ['ROOT'], 'abce')
592
        # both sides merge, discarding others' changes
593
        self.add_version('LCA1', ['REV1', 'REV2'], 'abcd')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
594
        self.add_version('LCA2', ['REV1', 'REV2'], 'fabce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
595
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
596
        self.assertEqual([('new-b', 'f\n'),
597
                          ('unchanged', 'a\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
598
                          ('unchanged', 'b\n'),
599
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
600
                          ('conflicted-a', 'd\n'),
601
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
602
                         ], list(plan))
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
603
604
605
class TestMergeImplementation(object):
606
607
    def do_merge(self, target_tree, source_tree, **kwargs):
608
        merger = _mod_merge.Merger.from_revision_ids(progress.DummyProgress(),
609
            target_tree, source_tree.last_revision(),
610
            other_branch=source_tree.branch)
611
        merger.merge_type=self.merge_type
612
        for name, value in kwargs.items():
613
            setattr(merger, name, value)
614
        merger.do_merge()
615
616
    def test_merge_specific_file(self):
617
        this_tree = self.make_branch_and_tree('this')
618
        this_tree.lock_write()
619
        self.addCleanup(this_tree.unlock)
620
        self.build_tree_contents([
621
            ('this/file1', 'a\nb\n'),
622
            ('this/file2', 'a\nb\n')
623
        ])
624
        this_tree.add(['file1', 'file2'])
625
        this_tree.commit('Added files')
626
        other_tree = this_tree.bzrdir.sprout('other').open_workingtree()
627
        self.build_tree_contents([
628
            ('other/file1', 'a\nb\nc\n'),
629
            ('other/file2', 'a\nb\nc\n')
630
        ])
631
        other_tree.commit('modified both')
632
        self.build_tree_contents([
633
            ('this/file1', 'd\na\nb\n'),
634
            ('this/file2', 'd\na\nb\n')
635
        ])
636
        this_tree.commit('modified both')
637
        self.do_merge(this_tree, other_tree, interesting_files=['file1'])
638
        self.assertFileEqual('d\na\nb\nc\n', 'this/file1')
639
        self.assertFileEqual('d\na\nb\n', 'this/file2')
640
641
642
class TestMerge3Merge(TestCaseWithTransport, TestMergeImplementation):
643
644
    merge_type = _mod_merge.Merge3Merger
645
646
647
class TestWeaveMerge(TestCaseWithTransport, TestMergeImplementation):
648
649
    merge_type = _mod_merge.WeaveMerger
650
651
652
class TestLCAMerge(TestCaseWithTransport, TestMergeImplementation):
653
654
    merge_type = _mod_merge.LCAMerger