/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1
# Copyright (C) 2005-2012, 2016 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
16
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
17
import os
18
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
19
from .. import (
5246.2.34 by Andrew Bennetts
Delete test_merge_into, and put those tests directly in test_merge.
20
    branch as _mod_branch,
21
    cleanup,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
22
    conflicts,
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
23
    errors,
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
24
    memorytree,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
25
    merge as _mod_merge,
26
    option,
5246.2.34 by Andrew Bennetts
Delete test_merge_into, and put those tests directly in test_merge.
27
    revision as _mod_revision,
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
28
    tests,
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
29
    transform,
6670.4.1 by Jelmer Vernooij
Update imports.
30
    )
31
from ..bzr import (
32
    inventory,
33
    knit,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
34
    versionedfile,
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
35
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
36
from ..conflicts import ConflictList, TextConflict
37
from ..errors import UnrelatedBranches, NoCommits
38
from ..merge import transform_tree, merge_inner, _PlanMerge
39
from ..osutils import basename, pathjoin, file_kind
40
from . import (
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
41
    features,
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
42
    TestCaseWithMemoryTransport,
43
    TestCaseWithTransport,
44
    test_merge_core,
45
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
46
from ..workingtree import WorkingTree
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
47
4634.101.8 by John Arbash Meinel
Add the criss-cross flip-flop 'bug' for weave merge.
48
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
49
class TestMerge(TestCaseWithTransport):
974.1.56 by aaron.bentley at utoronto
Added merge test
50
    """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.
51
974.1.56 by aaron.bentley at utoronto
Added merge test
52
    def test_pending(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
53
        wt = self.make_branch_and_tree('.')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
54
        rev_a = wt.commit("lala!")
55
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
56
        self.assertRaises(errors.PointlessMerge, wt.merge_from_branch,
57
                          wt.branch)
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
58
        self.assertEqual([rev_a], wt.get_parent_ids())
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
59
        return wt
974.1.80 by Aaron Bentley
Improved merge error handling and testing
60
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
61
    def test_undo(self):
62
        wt = self.make_branch_and_tree('.')
63
        wt.commit("lala!")
64
        wt.commit("haha!")
65
        wt.commit("blabla!")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
66
        wt.merge_from_branch(wt.branch, wt.branch.get_rev_id(2),
67
                             wt.branch.get_rev_id(1))
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
68
974.1.80 by Aaron Bentley
Improved merge error handling and testing
69
    def test_nocommits(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
70
        wt = self.test_pending()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
71
        wt2 = self.make_branch_and_tree('branch2')
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
72
        self.assertRaises(NoCommits, wt.merge_from_branch, wt2.branch)
73
        return wt, wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
74
75
    def test_unrelated(self):
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
76
        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.
77
        wt2.commit("blah")
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
78
        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.
79
        return wt2
974.1.80 by Aaron Bentley
Improved merge error handling and testing
80
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
81
    def test_merge_one_file(self):
82
        """Do a partial merge of a tree which should not affect tree parents."""
1645.1.1 by Aaron Bentley
Implement single-file merge
83
        wt1 = self.make_branch_and_tree('branch1')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
84
        tip = wt1.commit('empty commit')
1645.1.1 by Aaron Bentley
Implement single-file merge
85
        wt2 = self.make_branch_and_tree('branch2')
86
        wt2.pull(wt1.branch)
6423.1.1 by Vincent Ladeuil
Cleanup old blackbox tests and then some. Remove os.chdir() calls, caught a few bugs, make sure we don't leave file handles opened.
87
        with file('branch1/foo', 'wb') as f:
88
            f.write('foo')
89
        with file('branch1/bar', 'wb') as f:
90
            f.write('bar')
1645.1.1 by Aaron Bentley
Implement single-file merge
91
        wt1.add('foo')
92
        wt1.add('bar')
93
        wt1.commit('add foobar')
6423.1.1 by Vincent Ladeuil
Cleanup old blackbox tests and then some. Remove os.chdir() calls, caught a few bugs, make sure we don't leave file handles opened.
94
        self.run_bzr('merge ../branch1/baz', retcode=3, working_dir='branch2')
95
        self.run_bzr('merge ../branch1/foo', working_dir='branch2')
96
        self.assertPathExists('branch2/foo')
97
        self.assertPathDoesNotExist('branch2/bar')
98
        wt2 = WorkingTree.open('branch2')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
99
        self.assertEqual([tip], wt2.get_parent_ids())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
100
974.1.88 by Aaron Bentley
Set a pending_merge if the merge base is forced to revno 0
101
    def test_pending_with_null(self):
1551.8.25 by Aaron Bentley
Fix deprecated use of pending_merges
102
        """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.
103
        wt2 = self.test_unrelated()
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
104
        wt1 = WorkingTree.open('.')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
105
        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.
106
        br1.fetch(wt2.branch)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
107
        # merge all of branch 2 into branch 1 even though they
1390 by Robert Collins
pair programming worx... merge integration and weave
108
        # are not related.
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
109
        wt1.merge_from_branch(wt2.branch, wt2.last_revision(), 'null:')
1908.6.11 by Robert Collins
Remove usage of tree.pending_merges().
110
        self.assertEqual([br1.last_revision(), wt2.branch.last_revision()],
111
            wt1.get_parent_ids())
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
112
        return (wt1, wt2.branch)
974.1.89 by Aaron Bentley
Fixed merging with multiple roots, by using null as graph root.
113
114
    def test_two_roots(self):
115
        """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.
116
        wt1, br2 = self.test_pending_with_null()
117
        wt1.commit("blah")
3228.4.15 by John Arbash Meinel
Stop using common_ancestor
118
        wt1.lock_read()
119
        try:
120
            last = wt1.branch.last_revision()
121
            last2 = br2.last_revision()
122
            graph = wt1.branch.repository.get_graph()
123
            self.assertEqual(last2, graph.find_unique_lca(last, last2))
124
        finally:
125
            wt1.unlock()
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
126
5954.4.2 by Aaron Bentley
Support merging into null tree.
127
    def test_merge_into_null_tree(self):
128
        wt = self.make_branch_and_tree('tree')
129
        null_tree = wt.basis_tree()
130
        self.build_tree(['tree/file'])
131
        wt.add('file')
132
        wt.commit('tree with root')
133
        merger = _mod_merge.Merge3Merger(null_tree, null_tree, null_tree, wt,
134
                                         this_branch=wt.branch,
135
                                         do_merge=False)
136
        with merger.make_preview_transform() as tt:
137
            self.assertEqual([], tt.find_conflicts())
138
            preview = tt.get_preview_tree()
139
            self.assertEqual(wt.get_root_id(), preview.get_root_id())
140
6011.1.1 by Aaron Bentley
Merging an unrelated tree retains root.
141
    def test_merge_unrelated_retains_root(self):
142
        wt = self.make_branch_and_tree('tree')
6024.1.2 by Aaron Bentley
Explicitly test transform in test case.
143
        other_tree = self.make_branch_and_tree('other')
144
        self.addCleanup(other_tree.lock_read().unlock)
6011.1.7 by Vincent Ladeuil
Change test order to get a better diff.
145
        merger = _mod_merge.Merge3Merger(wt, wt, wt.basis_tree(), other_tree,
146
                                         this_branch=wt.branch,
147
                                         do_merge=False)
6024.1.2 by Aaron Bentley
Explicitly test transform in test case.
148
        with transform.TransformPreview(wt) as merger.tt:
149
            merger._compute_transform()
150
            new_root_id = merger.tt.final_file_id(merger.tt.root)
151
            self.assertEqual(wt.get_root_id(), new_root_id)
6011.1.7 by Vincent Ladeuil
Change test order to get a better diff.
152
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
153
    def test_create_rename(self):
154
        """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.
155
        tree =self.make_branch_and_tree('.')
6437.20.3 by Wouter van Heyst
mechanically replace file().write() pattern with a with-keyword version
156
        with file('name1', 'wb') as f: f.write('Hello')
1185.46.1 by Aaron Bentley
Test case when file to be renamed is also deleted
157
        tree.add('name1')
158
        tree.commit(message="hello")
159
        tree.rename_one('name1', 'name2')
160
        os.unlink('name2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
161
        transform_tree(tree, tree.branch.basis_tree())
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
162
163
    def test_layered_rename(self):
164
        """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.
165
        tree =self.make_branch_and_tree('.')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
166
        os.mkdir('dirname1')
167
        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 \
168
        filename = pathjoin('dirname1', 'name1')
6437.20.3 by Wouter van Heyst
mechanically replace file().write() pattern with a with-keyword version
169
        with file(filename, 'wb') as f: f.write('Hello')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
170
        tree.add(filename)
171
        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 \
172
        filename2 = pathjoin('dirname1', 'name2')
1185.46.2 by Aaron Bentley
Added test for renaming both parent and child
173
        tree.rename_one(filename, filename2)
174
        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.
175
        transform_tree(tree, tree.branch.basis_tree())
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
176
177
    def test_ignore_zero_merge_inner(self):
1907.4.1 by Matthieu Moy
Fixed merge to work nicely with -r revno:N:path
178
        # Test that merge_inner's ignore zero parameter is effective
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
179
        tree_a =self.make_branch_and_tree('a')
180
        tree_a.commit(message="hello")
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
181
        dir_b = tree_a.controldir.sprout('b')
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
182
        tree_b = dir_b.open_workingtree()
3146.4.4 by Aaron Bentley
Add write lock, so merge_inner works properly
183
        tree_b.lock_write()
184
        self.addCleanup(tree_b.unlock)
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
185
        tree_a.commit(message="hello again")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
186
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
187
                    this_tree=tree_b, ignore_zero=True)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
188
        self.assertTrue('All changes applied successfully.\n' not in
4794.1.15 by Robert Collins
Review feedback.
189
            self.get_log())
2796.1.3 by Aaron Bentley
update new test case
190
        tree_b.revert()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
191
        merge_inner(tree_b.branch, tree_a, tree_b.basis_tree(),
1551.2.23 by Aaron Bentley
Got merge_inner's ignore_zero parameter working
192
                    this_tree=tree_b, ignore_zero=False)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
193
        self.assertTrue('All changes applied successfully.\n' in self.get_log())
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
194
195
    def test_merge_inner_conflicts(self):
196
        tree_a = self.make_branch_and_tree('a')
197
        tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
198
        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.
199
        self.assertEqual(1, len(tree_a.conflicts()))
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
200
201
    def test_rmdir_conflict(self):
202
        tree_a = self.make_branch_and_tree('a')
203
        self.build_tree(['a/b/'])
204
        tree_a.add('b', 'b-id')
205
        tree_a.commit('added b')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
206
        # basis_tree() is only guaranteed to be valid as long as it is actually
207
        # the basis tree. This mutates the tree after grabbing basis, so go to
208
        # the repository.
209
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
210
        tree_z = tree_a.controldir.sprout('z').open_workingtree()
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
211
        self.build_tree(['a/b/c'])
212
        tree_a.add('b/c')
213
        tree_a.commit('added c')
214
        os.rmdir('z/b')
215
        tree_z.commit('removed b')
216
        merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
217
        self.assertEqual([
218
            conflicts.MissingParent('Created directory', 'b', 'b-id'),
219
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
220
            tree_z.conflicts())
2255.2.216 by Robert Collins
simplify merge_nested tests.
221
        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
222
                    this_tree=tree_a)
223
        self.assertEqual([
224
            conflicts.DeletingParent('Not deleting', 'b', 'b-id'),
225
            conflicts.UnversionedParent('Versioned directory', 'b', 'b-id')],
226
            tree_a.conflicts())
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
227
2100.3.29 by Aaron Bentley
Get merge working initially
228
    def test_nested_merge(self):
6700.1.3 by Jelmer Vernooij
Drop support for committing using record_entr_contents.
229
        self.knownFailure(
230
            'iter_changes doesn\'t work with changes in nested trees')
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
231
        tree = self.make_branch_and_tree('tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
232
            format='development-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
233
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
234
            format='development-subtree')
2100.3.29 by Aaron Bentley
Get merge working initially
235
        sub_tree.set_root_id('sub-tree-root')
236
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
237
        sub_tree.add('file')
238
        sub_tree.commit('foo')
239
        tree.add_reference(sub_tree)
240
        tree.commit('set text to 1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
241
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
2255.2.217 by Martin Pool
docs
242
        # modify the file in the subtree
2100.3.29 by Aaron Bentley
Get merge working initially
243
        self.build_tree_contents([('tree2/sub-tree/file', 'text2')])
2255.2.217 by Martin Pool
docs
244
        # and merge the changes from the diverged subtree into the containing
245
        # tree
2255.2.216 by Robert Collins
simplify merge_nested tests.
246
        tree2.commit('changed file text')
2100.3.29 by Aaron Bentley
Get merge working initially
247
        tree.merge_from_branch(tree2.branch)
248
        self.assertFileEqual('text2', 'tree/sub-tree/file')
249
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
250
    def test_merge_with_missing(self):
251
        tree_a = self.make_branch_and_tree('tree_a')
252
        self.build_tree_contents([('tree_a/file', 'content_1')])
253
        tree_a.add('file')
254
        tree_a.commit('commit base')
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
255
        # basis_tree() is only guaranteed to be valid as long as it is actually
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
256
        # the basis tree. This test commits to the tree after grabbing basis,
257
        # so we go to the repository.
2255.7.12 by John Arbash Meinel
Some comments on merge code, fix merge tests that
258
        base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision())
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
259
        tree_b = tree_a.controldir.sprout('tree_b').open_workingtree()
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
260
        self.build_tree_contents([('tree_a/file', 'content_2')])
261
        tree_a.commit('commit other')
262
        other_tree = tree_a.basis_tree()
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
263
        # 'file' is now missing but isn't altered in any commit in b so no
264
        # change should be applied.
1551.10.2 by Aaron Bentley
Handle merge with dangling inventory entries
265
        os.unlink('tree_b/file')
266
        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
267
268
    def test_merge_kind_change(self):
269
        tree_a = self.make_branch_and_tree('tree_a')
270
        self.build_tree_contents([('tree_a/file', 'content_1')])
271
        tree_a.add('file', 'file-id')
272
        tree_a.commit('added file')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
273
        tree_b = tree_a.controldir.sprout('tree_b').open_workingtree()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
274
        os.unlink('tree_a/file')
275
        self.build_tree(['tree_a/file/'])
276
        tree_a.commit('changed file to directory')
277
        tree_b.merge_from_branch(tree_a.branch)
278
        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'
279
        tree_b.revert()
1959.4.6 by Aaron Bentley
Ensure merge works across kind changes
280
        self.assertEqual('file', file_kind('tree_b/file'))
281
        self.build_tree_contents([('tree_b/file', 'content_2')])
282
        tree_b.commit('content change')
283
        tree_b.merge_from_branch(tree_a.branch)
284
        self.assertEqual(tree_b.conflicts(),
285
                         [conflicts.ContentsConflict('file',
286
                          file_id='file-id')])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
287
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
288
    def test_merge_type_registry(self):
289
        merge_type_option = option.Option.OPTIONS['merge-type']
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
290
        self.assertFalse('merge4' in [x[0] for x in
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
291
                        merge_type_option.iter_switches()])
292
        registry = _mod_merge.get_merge_type_registry()
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
293
        registry.register_lazy('merge4', 'breezy.merge', 'Merge4Merger',
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
294
                               'time-travelling merge')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
295
        self.assertTrue('merge4' in [x[0] for x in
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
296
                        merge_type_option.iter_switches()])
297
        registry.remove('merge4')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
298
        self.assertFalse('merge4' in [x[0] for x in
2221.4.16 by Aaron Bentley
Add tests for get_merge_type_registry
299
                        merge_type_option.iter_switches()])
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
300
1551.16.3 by Aaron Bentley
Rename test case
301
    def test_merge_other_moves_we_deleted(self):
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
302
        tree_a = self.make_branch_and_tree('A')
303
        tree_a.lock_write()
304
        self.addCleanup(tree_a.unlock)
305
        self.build_tree(['A/a'])
306
        tree_a.add('a')
307
        tree_a.commit('1', rev_id='rev-1')
308
        tree_a.flush()
309
        tree_a.rename_one('a', 'b')
310
        tree_a.commit('2')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
311
        bzrdir_b = tree_a.controldir.sprout('B', revision_id='rev-1')
1551.16.2 by Aaron Bentley
Don't crash on merging renamed deleted files (#110279)
312
        tree_b = bzrdir_b.open_workingtree()
313
        tree_b.lock_write()
314
        self.addCleanup(tree_b.unlock)
315
        os.unlink('B/a')
316
        tree_b.commit('3')
317
        try:
318
            tree_b.merge_from_branch(tree_a.branch)
319
        except AttributeError:
320
            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()
321
4685.2.1 by Gary van der Merwe
Revert rename of test_merge_uncommitted_otherbasis_ancestor_of_thisbasis.
322
    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()
323
        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.
324
        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()
325
        tree_a.add(['file_1'])
326
        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.
327
        tree_a.add(['file_2'])
328
        tree_a.commit('commit 2')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
329
        tree_b = tree_a.controldir.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.
330
        tree_b.rename_one('file_1', 'renamed')
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
331
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
1551.15.72 by Aaron Bentley
remove builtins._merge_helper
332
        merger.merge_type = _mod_merge.Merge3Merger
333
        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.
334
        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
335
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
336
    def test_merge_uncommitted_otherbasis_ancestor_of_thisbasis_weave(self):
337
        tree_a = self.make_branch_and_tree('a')
338
        self.build_tree(['a/file_1', 'a/file_2'])
339
        tree_a.add(['file_1'])
340
        tree_a.commit('commit 1')
341
        tree_a.add(['file_2'])
342
        tree_a.commit('commit 2')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
343
        tree_b = tree_a.controldir.sprout('b').open_workingtree()
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
344
        tree_b.rename_one('file_1', 'renamed')
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
345
        merger = _mod_merge.Merger.from_uncommitted(tree_a, tree_b)
3146.5.1 by Aaron Bentley
Make merge --uncommitted work with merge-type weave
346
        merger.merge_type = _mod_merge.WeaveMerger
347
        merger.do_merge()
348
        self.assertEqual(tree_a.get_parent_ids(), [tree_b.last_revision()])
349
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
350
    def prepare_cherrypick(self):
3062.2.13 by Aaron Bentley
Update prepare_cherrypick docstring
351
        """Prepare a pair of trees for cherrypicking tests.
352
353
        Both trees have a file, 'file'.
354
        rev1 sets content to 'a'.
355
        rev2b adds 'b'.
356
        rev3b adds 'c'.
357
        A full merge of rev2b and rev3b into this_tree would add both 'b' and
358
        'c'.  A successful cherrypick of rev2b-rev3b into this_tree will add
359
        'c', but not 'b'.
360
        """
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
361
        this_tree = self.make_branch_and_tree('this')
362
        self.build_tree_contents([('this/file', "a\n")])
363
        this_tree.add('file')
364
        this_tree.commit('rev1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
365
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
366
        self.build_tree_contents([('other/file', "a\nb\n")])
367
        other_tree.commit('rev2b', rev_id='rev2b')
368
        self.build_tree_contents([('other/file', "c\na\nb\n")])
369
        other_tree.commit('rev3b', rev_id='rev3b')
370
        this_tree.lock_write()
371
        self.addCleanup(this_tree.unlock)
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
372
        return this_tree, other_tree
373
374
    def test_weave_cherrypick(self):
375
        this_tree, other_tree = self.prepare_cherrypick()
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
376
        merger = _mod_merge.Merger.from_revision_ids(
3062.2.6 by Aaron Bentley
Get cherrypick-on-weave working
377
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
378
        merger.merge_type = _mod_merge.WeaveMerger
379
        merger.do_merge()
380
        self.assertFileEqual('c\na\n', 'this/file')
381
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
382
    def test_weave_cannot_reverse_cherrypick(self):
383
        this_tree, other_tree = self.prepare_cherrypick()
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
384
        merger = _mod_merge.Merger.from_revision_ids(
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
385
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
386
        merger.merge_type = _mod_merge.WeaveMerger
387
        self.assertRaises(errors.CannotReverseCherrypick, merger.do_merge)
388
389
    def test_merge3_can_reverse_cherrypick(self):
390
        this_tree, other_tree = self.prepare_cherrypick()
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
391
        merger = _mod_merge.Merger.from_revision_ids(
3062.2.7 by Aaron Bentley
Prevent reverse cherry-picking with weave
392
            this_tree, 'rev2b', 'rev3b', other_tree.branch)
393
        merger.merge_type = _mod_merge.Merge3Merger
394
        merger.do_merge()
395
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
396
    def test_merge3_will_detect_cherrypick(self):
397
        this_tree = self.make_branch_and_tree('this')
398
        self.build_tree_contents([('this/file', "a\n")])
399
        this_tree.add('file')
400
        this_tree.commit('rev1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
401
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
402
        self.build_tree_contents([('other/file', "a\nb\n")])
403
        other_tree.commit('rev2b', rev_id='rev2b')
404
        self.build_tree_contents([('other/file', "a\nb\nc\n")])
405
        other_tree.commit('rev3b', rev_id='rev3b')
406
        this_tree.lock_write()
407
        self.addCleanup(this_tree.unlock)
408
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
409
        merger = _mod_merge.Merger.from_revision_ids(
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
410
            this_tree, 'rev3b', 'rev2b', other_tree.branch)
411
        merger.merge_type = _mod_merge.Merge3Merger
412
        merger.do_merge()
413
        self.assertFileEqual('a\n'
414
                             '<<<<<<< TREE\n'
415
                             '=======\n'
416
                             'c\n'
417
                             '>>>>>>> MERGE-SOURCE\n',
418
                             'this/file')
419
5954.4.2 by Aaron Bentley
Support merging into null tree.
420
    def test_merge_reverse_revision_range(self):
421
        tree = self.make_branch_and_tree(".")
422
        tree.lock_write()
423
        self.addCleanup(tree.unlock)
424
        self.build_tree(['a'])
425
        tree.add('a')
6165.4.4 by Jelmer Vernooij
Avoid .revision_history().
426
        first_rev = tree.commit("added a")
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
427
        merger = _mod_merge.Merger.from_revision_ids(tree,
5954.4.2 by Aaron Bentley
Support merging into null tree.
428
                                          _mod_revision.NULL_REVISION,
429
                                          first_rev)
430
        merger.merge_type = _mod_merge.Merge3Merger
431
        merger.interesting_files = 'a'
432
        conflict_count = merger.do_merge()
433
        self.assertEqual(0, conflict_count)
434
435
        self.assertPathDoesNotExist("a")
436
        tree.revert()
437
        self.assertPathExists("a")
438
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
439
    def test_make_merger(self):
440
        this_tree = self.make_branch_and_tree('this')
441
        this_tree.commit('rev1', rev_id='rev1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
442
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
443
        this_tree.commit('rev2', rev_id='rev2a')
444
        other_tree.commit('rev2', rev_id='rev2b')
445
        this_tree.lock_write()
446
        self.addCleanup(this_tree.unlock)
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
447
        merger = _mod_merge.Merger.from_revision_ids(
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
448
            this_tree, 'rev2b', other_branch=other_tree.branch)
449
        merger.merge_type = _mod_merge.Merge3Merger
450
        tree_merger = merger.make_merger()
451
        self.assertIs(_mod_merge.Merge3Merger, tree_merger.__class__)
6410.1.1 by Jelmer Vernooij
Add other_branch argument to Merge3Merger.
452
        self.assertEqual('rev2b',
453
            tree_merger.other_tree.get_revision_id())
454
        self.assertEqual('rev1',
455
            tree_merger.base_tree.get_revision_id())
456
        self.assertEqual(other_tree.branch, tree_merger.other_branch)
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
457
458
    def test_make_preview_transform(self):
459
        this_tree = self.make_branch_and_tree('this')
460
        self.build_tree_contents([('this/file', '1\n')])
461
        this_tree.add('file', 'file-id')
462
        this_tree.commit('rev1', rev_id='rev1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
463
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
464
        self.build_tree_contents([('this/file', '1\n2a\n')])
465
        this_tree.commit('rev2', rev_id='rev2a')
466
        self.build_tree_contents([('other/file', '2b\n1\n')])
467
        other_tree.commit('rev2', rev_id='rev2b')
468
        this_tree.lock_write()
469
        self.addCleanup(this_tree.unlock)
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
470
        merger = _mod_merge.Merger.from_revision_ids(
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
471
            this_tree, 'rev2b', other_branch=other_tree.branch)
472
        merger.merge_type = _mod_merge.Merge3Merger
473
        tree_merger = merger.make_merger()
474
        tt = tree_merger.make_preview_transform()
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
475
        self.addCleanup(tt.finalize)
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
476
        preview_tree = tt.get_preview_tree()
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
477
        tree_file = this_tree.get_file('file')
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
478
        try:
479
            self.assertEqual('1\n2a\n', tree_file.read())
480
        finally:
481
            tree_file.close()
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
482
        preview_file = preview_tree.get_file('file')
3008.1.21 by Aaron Bentley
Make compute_transform private, test make_preview_transform
483
        try:
484
            self.assertEqual('2b\n1\n2a\n', preview_file.read())
485
        finally:
486
            preview_file.close()
487
3008.1.22 by Aaron Bentley
Get do_merge under test
488
    def test_do_merge(self):
489
        this_tree = self.make_branch_and_tree('this')
490
        self.build_tree_contents([('this/file', '1\n')])
491
        this_tree.add('file', 'file-id')
492
        this_tree.commit('rev1', rev_id='rev1')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
493
        other_tree = this_tree.controldir.sprout('other').open_workingtree()
3008.1.22 by Aaron Bentley
Get do_merge under test
494
        self.build_tree_contents([('this/file', '1\n2a\n')])
495
        this_tree.commit('rev2', rev_id='rev2a')
496
        self.build_tree_contents([('other/file', '2b\n1\n')])
497
        other_tree.commit('rev2', rev_id='rev2b')
498
        this_tree.lock_write()
499
        self.addCleanup(this_tree.unlock)
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
500
        merger = _mod_merge.Merger.from_revision_ids(
3008.1.22 by Aaron Bentley
Get do_merge under test
501
            this_tree, 'rev2b', other_branch=other_tree.branch)
502
        merger.merge_type = _mod_merge.Merge3Merger
503
        tree_merger = merger.make_merger()
504
        tt = tree_merger.do_merge()
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
505
        tree_file = this_tree.get_file('file')
3008.1.22 by Aaron Bentley
Get do_merge under test
506
        try:
507
            self.assertEqual('2b\n1\n2a\n', tree_file.read())
508
        finally:
509
            tree_file.close()
510
5993.2.3 by Jelmer Vernooij
Update NEWS, consistently use require_tree_root as argument everywhere.
511
    def test_merge_require_tree_root(self):
5993.2.2 by Jelmer Vernooij
Fix fixing up root ids.
512
        tree = self.make_branch_and_tree(".")
513
        tree.lock_write()
514
        self.addCleanup(tree.unlock)
515
        self.build_tree(['a'])
516
        tree.add('a')
6165.4.4 by Jelmer Vernooij
Avoid .revision_history().
517
        first_rev = tree.commit("added a")
5993.2.2 by Jelmer Vernooij
Fix fixing up root ids.
518
        old_root_id = tree.get_root_id()
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
519
        merger = _mod_merge.Merger.from_revision_ids(tree,
5993.2.2 by Jelmer Vernooij
Fix fixing up root ids.
520
                                          _mod_revision.NULL_REVISION,
521
                                          first_rev)
522
        merger.merge_type = _mod_merge.Merge3Merger
523
        conflict_count = merger.do_merge()
524
        self.assertEqual(0, conflict_count)
6825.5.1 by Jelmer Vernooij
Implement Tree.all_versioned_paths.
525
        self.assertEqual({''}, set(tree.all_versioned_paths()))
5993.2.2 by Jelmer Vernooij
Fix fixing up root ids.
526
        tree.set_parent_ids([])
527
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
528
    def test_merge_add_into_deleted_root(self):
529
        # Yes, people actually do this.  And report bugs if it breaks.
530
        source = self.make_branch_and_tree('source', format='rich-root-pack')
531
        self.build_tree(['source/foo/'])
532
        source.add('foo', 'foo-id')
533
        source.commit('Add foo')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
534
        target = source.controldir.sprout('target').open_workingtree()
6856 by Jelmer Vernooij
Merge lp:~jelmer/brz/is-versioned.
535
        subtree = target.extract('foo', 'foo-id')
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
536
        subtree.commit('Delete root')
537
        self.build_tree(['source/bar'])
538
        source.add('bar', 'bar-id')
539
        source.commit('Add bar')
540
        subtree.merge_from_branch(source.branch)
541
3649.3.1 by Jelmer Vernooij
Merging from a previously joined branch will no longer cause a traceback.
542
    def test_merge_joined_branch(self):
543
        source = self.make_branch_and_tree('source', format='rich-root-pack')
544
        self.build_tree(['source/foo'])
545
        source.add('foo')
546
        source.commit('Add foo')
547
        target = self.make_branch_and_tree('target', format='rich-root-pack')
548
        self.build_tree(['target/bla'])
549
        target.add('bla')
550
        target.commit('Add bla')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
551
        nested = source.controldir.sprout('target/subtree').open_workingtree()
3649.3.1 by Jelmer Vernooij
Merging from a previously joined branch will no longer cause a traceback.
552
        target.subsume(nested)
553
        target.commit('Join nested')
554
        self.build_tree(['source/bar'])
555
        source.add('bar')
556
        source.commit('Add bar')
557
        target.merge_from_branch(source.branch)
558
        target.commit('Merge source')
559
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
560
561
class TestPlanMerge(TestCaseWithMemoryTransport):
562
563
    def setUp(self):
6552.1.4 by Vincent Ladeuil
Remaining tests matching setup(self) that can be rewritten with super().
564
        super(TestPlanMerge, self).setUp()
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
565
        mapper = versionedfile.PrefixMapper()
566
        factory = knit.make_file_factory(True, mapper)
567
        self.vf = factory(self.get_transport())
568
        self.plan_merge_vf = versionedfile._PlanMergeVersionedFile('root')
569
        self.plan_merge_vf.fallback_versionedfiles.append(self.vf)
570
571
    def add_version(self, key, parents, text):
572
        self.vf.add_lines(key, parents, [c+'\n' for c in text])
573
3514.2.10 by John Arbash Meinel
Handle more edge cases.
574
    def add_rev(self, prefix, revision_id, parents, text):
575
        self.add_version((prefix, revision_id), [(prefix, p) for p in parents],
576
                         text)
577
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
578
    def add_uncommitted_version(self, key, parents, text):
579
        self.plan_merge_vf.add_lines(key, parents,
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
580
                                     [c+'\n' for c in text])
581
582
    def setup_plan_merge(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
583
        self.add_rev('root', 'A', [], 'abc')
584
        self.add_rev('root', 'B', ['A'], 'acehg')
585
        self.add_rev('root', 'C', ['A'], 'fabg')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
586
        return _PlanMerge('B', 'C', self.plan_merge_vf, ('root',))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
587
588
    def setup_plan_merge_uncommitted(self):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
589
        self.add_version(('root', 'A'), [], 'abc')
590
        self.add_uncommitted_version(('root', 'B:'), [('root', 'A')], 'acehg')
591
        self.add_uncommitted_version(('root', 'C:'), [('root', 'A')], 'fabg')
592
        return _PlanMerge('B:', 'C:', self.plan_merge_vf, ('root',))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
593
4634.101.8 by John Arbash Meinel
Add the criss-cross flip-flop 'bug' for weave merge.
594
    def test_base_from_plan(self):
595
        self.setup_plan_merge()
596
        plan = self.plan_merge_vf.plan_merge('B', 'C')
597
        pwm = versionedfile.PlanWeaveMerge(plan)
598
        self.assertEqual(['a\n', 'b\n', 'c\n'], pwm.base_from_plan())
599
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
600
    def test_unique_lines(self):
601
        plan = self.setup_plan_merge()
602
        self.assertEqual(plan._unique_lines(
603
            plan._get_matching_blocks('B', 'C')),
604
            ([1, 2, 3], [0, 2]))
605
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
606
    def test_plan_merge(self):
607
        self.setup_plan_merge()
608
        plan = self.plan_merge_vf.plan_merge('B', 'C')
609
        self.assertEqual([
610
                          ('new-b', 'f\n'),
611
                          ('unchanged', 'a\n'),
612
                          ('killed-a', 'b\n'),
613
                          ('killed-b', 'c\n'),
614
                          ('new-a', 'e\n'),
615
                          ('new-a', 'h\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
616
                          ('new-a', 'g\n'),
617
                          ('new-b', 'g\n')],
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
618
                         list(plan))
619
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
620
    def test_plan_merge_cherrypick(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
621
        self.add_rev('root', 'A', [], 'abc')
622
        self.add_rev('root', 'B', ['A'], 'abcde')
623
        self.add_rev('root', 'C', ['A'], 'abcefg')
624
        self.add_rev('root', 'D', ['A', 'B', 'C'], 'abcdegh')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
625
        my_plan = _PlanMerge('B', 'D', self.plan_merge_vf, ('root',))
3514.2.11 by John Arbash Meinel
Shortcut the case when one revision is in the ancestry of the other.
626
        # We shortcut when one text supersedes the other in the per-file graph.
627
        # We don't actually need to compare the texts at this point.
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
628
        self.assertEqual([
3514.2.11 by John Arbash Meinel
Shortcut the case when one revision is in the ancestry of the other.
629
                          ('new-b', 'a\n'),
630
                          ('new-b', 'b\n'),
631
                          ('new-b', 'c\n'),
632
                          ('new-b', 'd\n'),
633
                          ('new-b', 'e\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
634
                          ('new-b', 'g\n'),
635
                          ('new-b', 'h\n')],
636
                          list(my_plan.plan_merge()))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
637
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
638
    def test_plan_merge_no_common_ancestor(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
639
        self.add_rev('root', 'A', [], 'abc')
640
        self.add_rev('root', 'B', [], 'xyz')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
641
        my_plan = _PlanMerge('A', 'B', self.plan_merge_vf, ('root',))
642
        self.assertEqual([
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
643
                          ('new-a', 'a\n'),
644
                          ('new-a', 'b\n'),
645
                          ('new-a', 'c\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
646
                          ('new-b', 'x\n'),
647
                          ('new-b', 'y\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
648
                          ('new-b', 'z\n')],
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
649
                          list(my_plan.plan_merge()))
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
650
3514.2.10 by John Arbash Meinel
Handle more edge cases.
651
    def test_plan_merge_tail_ancestors(self):
652
        # The graph looks like this:
653
        #       A       # Common to all ancestors
654
        #      / \
655
        #     B   C     # Ancestors of E, only common to one side
656
        #     |\ /|
657
        #     D E F     # D, F are unique to G, H respectively
658
        #     |/ \|     # E is the LCA for G & H, and the unique LCA for
659
        #     G   H     # I, J
660
        #     |\ /|
661
        #     | X |
662
        #     |/ \|
663
        #     I   J     # criss-cross merge of G, H
664
        #
665
        # In this situation, a simple pruning of ancestors of E will leave D &
666
        # F "dangling", which looks like they introduce lines different from
667
        # the ones in E, but in actuality C&B introduced the lines, and they
668
        # are already present in E
669
670
        # Introduce the base text
671
        self.add_rev('root', 'A', [], 'abc')
672
        # Introduces a new line B
673
        self.add_rev('root', 'B', ['A'], 'aBbc')
674
        # Introduces a new line C
675
        self.add_rev('root', 'C', ['A'], 'abCc')
676
        # Introduce new line D
677
        self.add_rev('root', 'D', ['B'], 'DaBbc')
678
        # Merges B and C by just incorporating both
679
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
680
        # Introduce new line F
681
        self.add_rev('root', 'F', ['C'], 'abCcF')
682
        # Merge D & E by just combining the texts
683
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
684
        # Merge F & E by just combining the texts
685
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
686
        # Merge G & H by just combining texts
687
        self.add_rev('root', 'I', ['G', 'H'], 'DaBbCcF')
688
        # Merge G & H but supersede an old line in B
689
        self.add_rev('root', 'J', ['H', 'G'], 'DaJbCcF')
690
        plan = self.plan_merge_vf.plan_merge('I', 'J')
691
        self.assertEqual([
692
                          ('unchanged', 'D\n'),
693
                          ('unchanged', 'a\n'),
694
                          ('killed-b', 'B\n'),
695
                          ('new-b', 'J\n'),
696
                          ('unchanged', 'b\n'),
697
                          ('unchanged', 'C\n'),
698
                          ('unchanged', 'c\n'),
699
                          ('unchanged', 'F\n')],
700
                         list(plan))
701
702
    def test_plan_merge_tail_triple_ancestors(self):
703
        # The graph looks like this:
704
        #       A       # Common to all ancestors
705
        #      / \
706
        #     B   C     # Ancestors of E, only common to one side
707
        #     |\ /|
708
        #     D E F     # D, F are unique to G, H respectively
709
        #     |/|\|     # E is the LCA for G & H, and the unique LCA for
710
        #     G Q H     # I, J
711
        #     |\ /|     # Q is just an extra node which is merged into both
712
        #     | X |     # I and J
713
        #     |/ \|
714
        #     I   J     # criss-cross merge of G, H
715
        #
716
        # This is the same as the test_plan_merge_tail_ancestors, except we add
717
        # a third LCA that doesn't add new lines, but will trigger our more
718
        # involved ancestry logic
719
720
        self.add_rev('root', 'A', [], 'abc')
721
        self.add_rev('root', 'B', ['A'], 'aBbc')
722
        self.add_rev('root', 'C', ['A'], 'abCc')
723
        self.add_rev('root', 'D', ['B'], 'DaBbc')
724
        self.add_rev('root', 'E', ['B', 'C'], 'aBbCc')
725
        self.add_rev('root', 'F', ['C'], 'abCcF')
726
        self.add_rev('root', 'G', ['D', 'E'], 'DaBbCc')
727
        self.add_rev('root', 'H', ['F', 'E'], 'aBbCcF')
728
        self.add_rev('root', 'Q', ['E'], 'aBbCc')
729
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DaBbCcF')
730
        # Merge G & H but supersede an old line in B
731
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DaJbCcF')
732
        plan = self.plan_merge_vf.plan_merge('I', 'J')
733
        self.assertEqual([
734
                          ('unchanged', 'D\n'),
735
                          ('unchanged', 'a\n'),
736
                          ('killed-b', 'B\n'),
737
                          ('new-b', 'J\n'),
738
                          ('unchanged', 'b\n'),
739
                          ('unchanged', 'C\n'),
740
                          ('unchanged', 'c\n'),
741
                          ('unchanged', 'F\n')],
742
                         list(plan))
743
3514.2.14 by John Arbash Meinel
Bring in the code to collapse linear portions of the graph.
744
    def test_plan_merge_2_tail_triple_ancestors(self):
745
        # The graph looks like this:
746
        #     A   B     # 2 tails going back to NULL
747
        #     |\ /|
748
        #     D E F     # D, is unique to G, F to H
749
        #     |/|\|     # E is the LCA for G & H, and the unique LCA for
750
        #     G Q H     # I, J
751
        #     |\ /|     # Q is just an extra node which is merged into both
752
        #     | X |     # I and J
753
        #     |/ \|
754
        #     I   J     # criss-cross merge of G, H (and Q)
755
        #
756
757
        # This is meant to test after hitting a 3-way LCA, and multiple tail
758
        # ancestors (only have NULL_REVISION in common)
759
760
        self.add_rev('root', 'A', [], 'abc')
761
        self.add_rev('root', 'B', [], 'def')
762
        self.add_rev('root', 'D', ['A'], 'Dabc')
763
        self.add_rev('root', 'E', ['A', 'B'], 'abcdef')
764
        self.add_rev('root', 'F', ['B'], 'defF')
765
        self.add_rev('root', 'G', ['D', 'E'], 'Dabcdef')
766
        self.add_rev('root', 'H', ['F', 'E'], 'abcdefF')
767
        self.add_rev('root', 'Q', ['E'], 'abcdef')
768
        self.add_rev('root', 'I', ['G', 'Q', 'H'], 'DabcdefF')
769
        # Merge G & H but supersede an old line in B
770
        self.add_rev('root', 'J', ['H', 'Q', 'G'], 'DabcdJfF')
771
        plan = self.plan_merge_vf.plan_merge('I', 'J')
772
        self.assertEqual([
773
                          ('unchanged', 'D\n'),
774
                          ('unchanged', 'a\n'),
775
                          ('unchanged', 'b\n'),
776
                          ('unchanged', 'c\n'),
777
                          ('unchanged', 'd\n'),
778
                          ('killed-b', 'e\n'),
779
                          ('new-b', 'J\n'),
780
                          ('unchanged', 'f\n'),
781
                          ('unchanged', 'F\n')],
782
                         list(plan))
783
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
784
    def test_plan_merge_uncommitted_files(self):
3062.1.13 by Aaron Bentley
Make _PlanMerge an implementation detail of _PlanMergeVersionedFile
785
        self.setup_plan_merge_uncommitted()
786
        plan = self.plan_merge_vf.plan_merge('B:', 'C:')
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
787
        self.assertEqual([
788
                          ('new-b', 'f\n'),
789
                          ('unchanged', 'a\n'),
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
790
                          ('killed-a', 'b\n'),
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
791
                          ('killed-b', 'c\n'),
792
                          ('new-a', 'e\n'),
793
                          ('new-a', 'h\n'),
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
794
                          ('new-a', 'g\n'),
795
                          ('new-b', 'g\n')],
796
                         list(plan))
797
798
    def test_plan_merge_insert_order(self):
799
        """Weave merges are sensitive to the order of insertion.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
800
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
801
        Specifically for overlapping regions, it effects which region gets put
802
        'first'. And when a user resolves an overlapping merge, if they use the
803
        same ordering, then the lines match the parents, if they don't only
804
        *some* of the lines match.
805
        """
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
806
        self.add_rev('root', 'A', [], 'abcdef')
807
        self.add_rev('root', 'B', ['A'], 'abwxcdef')
808
        self.add_rev('root', 'C', ['A'], 'abyzcdef')
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
809
        # Merge, and resolve the conflict by adding *both* sets of lines
810
        # If we get the ordering wrong, these will look like new lines in D,
811
        # rather than carried over from B, C
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
812
        self.add_rev('root', 'D', ['B', 'C'],
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
813
                         'abwxyzcdef')
814
        # Supersede the lines in B and delete the lines in C, which will
815
        # conflict if they are treated as being in D
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
816
        self.add_rev('root', 'E', ['C', 'B'],
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
817
                         'abnocdef')
818
        # Same thing for the lines in C
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
819
        self.add_rev('root', 'F', ['C'], 'abpqcdef')
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
820
        plan = self.plan_merge_vf.plan_merge('D', 'E')
821
        self.assertEqual([
822
                          ('unchanged', 'a\n'),
823
                          ('unchanged', 'b\n'),
824
                          ('killed-b', 'w\n'),
825
                          ('killed-b', 'x\n'),
826
                          ('killed-b', 'y\n'),
827
                          ('killed-b', 'z\n'),
828
                          ('new-b', 'n\n'),
829
                          ('new-b', 'o\n'),
830
                          ('unchanged', 'c\n'),
831
                          ('unchanged', 'd\n'),
832
                          ('unchanged', 'e\n'),
833
                          ('unchanged', 'f\n')],
834
                         list(plan))
835
        plan = self.plan_merge_vf.plan_merge('E', 'D')
836
        # Going in the opposite direction shows the effect of the opposite plan
837
        self.assertEqual([
838
                          ('unchanged', 'a\n'),
839
                          ('unchanged', 'b\n'),
840
                          ('new-b', 'w\n'),
841
                          ('new-b', 'x\n'),
842
                          ('killed-a', 'y\n'),
843
                          ('killed-a', 'z\n'),
844
                          ('killed-both', 'w\n'),
845
                          ('killed-both', 'x\n'),
846
                          ('new-a', 'n\n'),
847
                          ('new-a', 'o\n'),
848
                          ('unchanged', 'c\n'),
849
                          ('unchanged', 'd\n'),
850
                          ('unchanged', 'e\n'),
851
                          ('unchanged', 'f\n')],
3062.1.9 by Aaron Bentley
Move PlanMerge into merge and _PlanMergeVersionedFile into versionedfile
852
                         list(plan))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
853
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
854
    def test_plan_merge_criss_cross(self):
855
        # This is specificly trying to trigger problems when using limited
856
        # ancestry and weaves. The ancestry graph looks like:
3514.2.8 by John Arbash Meinel
The insertion ordering into the weave has an impact on conflicts.
857
        #       XX      unused ancestor, should not show up in the weave
858
        #       |
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
859
        #       A       Unique LCA
860
        #       |\
861
        #       B \     Introduces a line 'foo'
862
        #      / \ \
863
        #     C   D E   C & D both have 'foo', E has different changes
864
        #     |\ /| |
865
        #     | X | |
866
        #     |/ \|/
867
        #     F   G      All of C, D, E are merged into F and G, so they are
868
        #                all common ancestors.
869
        #
870
        # The specific issue with weaves:
871
        #   B introduced a text ('foo') that is present in both C and D.
872
        #   If we do not include B (because it isn't an ancestor of E), then
873
        #   the A=>C and A=>D look like both sides independently introduce the
874
        #   text ('foo'). If F does not modify the text, it would still appear
875
        #   to have deleted on of the versions from C or D. If G then modifies
876
        #   'foo', it should appear as superseding the value in F (since it
877
        #   came from B), rather than conflict because of the resolution during
878
        #   C & D.
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
879
        self.add_rev('root', 'XX', [], 'qrs')
880
        self.add_rev('root', 'A', ['XX'], 'abcdef')
881
        self.add_rev('root', 'B', ['A'], 'axcdef')
882
        self.add_rev('root', 'C', ['B'], 'axcdefg')
883
        self.add_rev('root', 'D', ['B'], 'haxcdef')
884
        self.add_rev('root', 'E', ['A'], 'abcdyf')
885
        # Simple combining of all texts
886
        self.add_rev('root', 'F', ['C', 'D', 'E'], 'haxcdyfg')
887
        # combine and supersede 'x'
888
        self.add_rev('root', 'G', ['C', 'D', 'E'], 'hazcdyfg')
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
889
        plan = self.plan_merge_vf.plan_merge('F', 'G')
890
        self.assertEqual([
891
                          ('unchanged', 'h\n'),
892
                          ('unchanged', 'a\n'),
3514.2.7 by John Arbash Meinel
Fix the failing test by implementing the fallback logic.
893
                          ('killed-base', 'b\n'),
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
894
                          ('killed-b', 'x\n'),
895
                          ('new-b', 'z\n'),
896
                          ('unchanged', 'c\n'),
897
                          ('unchanged', 'd\n'),
898
                          ('killed-base', 'e\n'),
899
                          ('unchanged', 'y\n'),
900
                          ('unchanged', 'f\n'),
901
                          ('unchanged', 'g\n')],
902
                         list(plan))
4634.101.8 by John Arbash Meinel
Add the criss-cross flip-flop 'bug' for weave merge.
903
        plan = self.plan_merge_vf.plan_lca_merge('F', 'G')
904
        # This is one of the main differences between plan_merge and
905
        # plan_lca_merge. plan_lca_merge generates a conflict for 'x => z',
906
        # because 'x' was not present in one of the bases. However, in this
907
        # case it is spurious because 'x' does not exist in the global base A.
908
        self.assertEqual([
909
                          ('unchanged', 'h\n'),
910
                          ('unchanged', 'a\n'),
911
                          ('conflicted-a', 'x\n'),
912
                          ('new-b', 'z\n'),
913
                          ('unchanged', 'c\n'),
914
                          ('unchanged', 'd\n'),
915
                          ('unchanged', 'y\n'),
916
                          ('unchanged', 'f\n'),
917
                          ('unchanged', 'g\n')],
918
                         list(plan))
919
920
    def test_criss_cross_flip_flop(self):
921
        # This is specificly trying to trigger problems when using limited
922
        # ancestry and weaves. The ancestry graph looks like:
923
        #       XX      unused ancestor, should not show up in the weave
924
        #       |
925
        #       A       Unique LCA
926
        #      / \  
927
        #     B   C     B & C both introduce a new line
928
        #     |\ /|  
929
        #     | X |  
930
        #     |/ \| 
931
        #     D   E     B & C are both merged, so both are common ancestors
932
        #               In the process of merging, both sides order the new
933
        #               lines differently
934
        #
935
        self.add_rev('root', 'XX', [], 'qrs')
936
        self.add_rev('root', 'A', ['XX'], 'abcdef')
937
        self.add_rev('root', 'B', ['A'], 'abcdgef')
938
        self.add_rev('root', 'C', ['A'], 'abcdhef')
939
        self.add_rev('root', 'D', ['B', 'C'], 'abcdghef')
940
        self.add_rev('root', 'E', ['C', 'B'], 'abcdhgef')
941
        plan = list(self.plan_merge_vf.plan_merge('D', 'E'))
942
        self.assertEqual([
943
                          ('unchanged', 'a\n'),
944
                          ('unchanged', 'b\n'),
945
                          ('unchanged', 'c\n'),
946
                          ('unchanged', 'd\n'),
947
                          ('new-b', 'h\n'),
948
                          ('unchanged', 'g\n'),
949
                          ('killed-b', 'h\n'),
950
                          ('unchanged', 'e\n'),
951
                          ('unchanged', 'f\n'),
952
                         ], plan)
953
        pwm = versionedfile.PlanWeaveMerge(plan)
954
        self.assertEqualDiff('\n'.join('abcdghef') + '\n',
955
                             ''.join(pwm.base_from_plan()))
956
        # Reversing the order reverses the merge plan, and final order of 'hg'
957
        # => 'gh'
958
        plan = list(self.plan_merge_vf.plan_merge('E', 'D'))
959
        self.assertEqual([
960
                          ('unchanged', 'a\n'),
961
                          ('unchanged', 'b\n'),
962
                          ('unchanged', 'c\n'),
963
                          ('unchanged', 'd\n'),
964
                          ('new-b', 'g\n'),
965
                          ('unchanged', 'h\n'),
966
                          ('killed-b', 'g\n'),
967
                          ('unchanged', 'e\n'),
968
                          ('unchanged', 'f\n'),
969
                         ], plan)
970
        pwm = versionedfile.PlanWeaveMerge(plan)
971
        self.assertEqualDiff('\n'.join('abcdhgef') + '\n',
972
                             ''.join(pwm.base_from_plan()))
973
        # This is where lca differs, in that it (fairly correctly) determines
974
        # that there is a conflict because both sides resolved the merge
975
        # differently
976
        plan = list(self.plan_merge_vf.plan_lca_merge('D', 'E'))
977
        self.assertEqual([
978
                          ('unchanged', 'a\n'),
979
                          ('unchanged', 'b\n'),
980
                          ('unchanged', 'c\n'),
981
                          ('unchanged', 'd\n'),
982
                          ('conflicted-b', 'h\n'),
983
                          ('unchanged', 'g\n'),
984
                          ('conflicted-a', 'h\n'),
985
                          ('unchanged', 'e\n'),
986
                          ('unchanged', 'f\n'),
987
                         ], plan)
988
        pwm = versionedfile.PlanWeaveMerge(plan)
4634.101.9 by John Arbash Meinel
Reverse the .BASE values for --lca and conflicted lines.
989
        self.assertEqualDiff('\n'.join('abcdgef') + '\n',
4634.101.8 by John Arbash Meinel
Add the criss-cross flip-flop 'bug' for weave merge.
990
                             ''.join(pwm.base_from_plan()))
991
        # Reversing it changes what line is doubled, but still gives a
992
        # double-conflict
993
        plan = list(self.plan_merge_vf.plan_lca_merge('E', 'D'))
994
        self.assertEqual([
995
                          ('unchanged', 'a\n'),
996
                          ('unchanged', 'b\n'),
997
                          ('unchanged', 'c\n'),
998
                          ('unchanged', 'd\n'),
999
                          ('conflicted-b', 'g\n'),
1000
                          ('unchanged', 'h\n'),
1001
                          ('conflicted-a', 'g\n'),
1002
                          ('unchanged', 'e\n'),
1003
                          ('unchanged', 'f\n'),
1004
                         ], plan)
1005
        pwm = versionedfile.PlanWeaveMerge(plan)
4634.101.9 by John Arbash Meinel
Reverse the .BASE values for --lca and conflicted lines.
1006
        self.assertEqualDiff('\n'.join('abcdhef') + '\n',
4634.101.8 by John Arbash Meinel
Add the criss-cross flip-flop 'bug' for weave merge.
1007
                             ''.join(pwm.base_from_plan()))
3514.2.6 by John Arbash Meinel
Write a (failing) test for complex ancestry.
1008
3514.2.12 by John Arbash Meinel
Start refactoring into helper functions
1009
    def assertRemoveExternalReferences(self, filtered_parent_map,
1010
                                       child_map, tails, parent_map):
1011
        """Assert results for _PlanMerge._remove_external_references."""
1012
        (act_filtered_parent_map, act_child_map,
1013
         act_tails) = _PlanMerge._remove_external_references(parent_map)
1014
1015
        # The parent map *should* preserve ordering, but the ordering of
1016
        # children is not strictly defined
1017
        # child_map = dict((k, sorted(children))
1018
        #                  for k, children in child_map.iteritems())
1019
        # act_child_map = dict(k, sorted(children)
1020
        #                      for k, children in act_child_map.iteritems())
1021
        self.assertEqual(filtered_parent_map, act_filtered_parent_map)
1022
        self.assertEqual(child_map, act_child_map)
1023
        self.assertEqual(sorted(tails), sorted(act_tails))
1024
1025
    def test__remove_external_references(self):
1026
        # First, nothing to remove
1027
        self.assertRemoveExternalReferences({3: [2], 2: [1], 1: []},
1028
            {1: [2], 2: [3], 3: []}, [1], {3: [2], 2: [1], 1: []})
1029
        # The reverse direction
1030
        self.assertRemoveExternalReferences({1: [2], 2: [3], 3: []},
1031
            {3: [2], 2: [1], 1: []}, [3], {1: [2], 2: [3], 3: []})
1032
        # Extra references
1033
        self.assertRemoveExternalReferences({3: [2], 2: [1], 1: []},
1034
            {1: [2], 2: [3], 3: []}, [1], {3: [2, 4], 2: [1, 5], 1: [6]})
1035
        # Multiple tails
1036
        self.assertRemoveExternalReferences(
1037
            {4: [2, 3], 3: [], 2: [1], 1: []},
1038
            {1: [2], 2: [4], 3: [4], 4: []},
1039
            [1, 3],
1040
            {4: [2, 3], 3: [5], 2: [1], 1: [6]})
1041
        # Multiple children
1042
        self.assertRemoveExternalReferences(
1043
            {1: [3], 2: [3, 4], 3: [], 4: []},
1044
            {1: [], 2: [], 3: [1, 2], 4: [2]},
1045
            [3, 4],
1046
            {1: [3], 2: [3, 4], 3: [5], 4: []})
1047
3514.2.13 by John Arbash Meinel
Add the ability to prune extra tails from the parent_map.
1048
    def assertPruneTails(self, pruned_map, tails, parent_map):
1049
        child_map = {}
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
1050
        for key, parent_keys in parent_map.items():
3514.2.13 by John Arbash Meinel
Add the ability to prune extra tails from the parent_map.
1051
            child_map.setdefault(key, [])
1052
            for pkey in parent_keys:
1053
                child_map.setdefault(pkey, []).append(key)
1054
        _PlanMerge._prune_tails(parent_map, child_map, tails)
1055
        self.assertEqual(pruned_map, parent_map)
1056
1057
    def test__prune_tails(self):
1058
        # Nothing requested to prune
1059
        self.assertPruneTails({1: [], 2: [], 3: []}, [],
1060
                              {1: [], 2: [], 3: []})
1061
        # Prune a single entry
1062
        self.assertPruneTails({1: [], 3: []}, [2],
1063
                              {1: [], 2: [], 3: []})
1064
        # Prune a chain
1065
        self.assertPruneTails({1: []}, [3],
1066
                              {1: [], 2: [3], 3: []})
1067
        # Prune a chain with a diamond
1068
        self.assertPruneTails({1: []}, [5],
1069
                              {1: [], 2: [3, 4], 3: [5], 4: [5], 5: []})
1070
        # Prune a partial chain
1071
        self.assertPruneTails({1: [6], 6:[]}, [5],
1072
                              {1: [2, 6], 2: [3, 4], 3: [5], 4: [5], 5: [],
1073
                               6: []})
1074
        # Prune a chain with multiple tips, that pulls out intermediates
1075
        self.assertPruneTails({1:[3], 3:[]}, [4, 5],
1076
                              {1: [2, 3], 2: [4, 5], 3: [], 4:[], 5:[]})
1077
        self.assertPruneTails({1:[3], 3:[]}, [5, 4],
1078
                              {1: [2, 3], 2: [4, 5], 3: [], 4:[], 5:[]})
1079
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
1080
    def test_subtract_plans(self):
1081
        old_plan = [
1082
        ('unchanged', 'a\n'),
1083
        ('new-a', 'b\n'),
1084
        ('killed-a', 'c\n'),
1085
        ('new-b', 'd\n'),
1086
        ('new-b', 'e\n'),
1087
        ('killed-b', 'f\n'),
1088
        ('killed-b', 'g\n'),
1089
        ]
1090
        new_plan = [
1091
        ('unchanged', 'a\n'),
1092
        ('new-a', 'b\n'),
1093
        ('killed-a', 'c\n'),
1094
        ('new-b', 'd\n'),
1095
        ('new-b', 'h\n'),
1096
        ('killed-b', 'f\n'),
1097
        ('killed-b', 'i\n'),
1098
        ]
1099
        subtracted_plan = [
1100
        ('unchanged', 'a\n'),
1101
        ('new-a', 'b\n'),
1102
        ('killed-a', 'c\n'),
1103
        ('new-b', 'h\n'),
1104
        ('unchanged', 'f\n'),
1105
        ('killed-b', 'i\n'),
1106
        ]
1107
        self.assertEqual(subtracted_plan,
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
1108
            list(_PlanMerge._subtract_plans(old_plan, new_plan)))
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
1109
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1110
    def setup_merge_with_base(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
1111
        self.add_rev('root', 'COMMON', [], 'abc')
1112
        self.add_rev('root', 'THIS', ['COMMON'], 'abcd')
1113
        self.add_rev('root', 'BASE', ['COMMON'], 'eabc')
1114
        self.add_rev('root', 'OTHER', ['BASE'], 'eafb')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1115
1116
    def test_plan_merge_with_base(self):
1117
        self.setup_merge_with_base()
3062.2.3 by Aaron Bentley
Sync up with bzr.dev API changes
1118
        plan = self.plan_merge_vf.plan_merge('THIS', 'OTHER', 'BASE')
3062.2.1 by Aaron Bentley
Add support for plan-merge with a base
1119
        self.assertEqual([('unchanged', 'a\n'),
1120
                          ('new-b', 'f\n'),
1121
                          ('unchanged', 'b\n'),
1122
                          ('killed-b', 'c\n'),
1123
                          ('new-a', 'd\n')
1124
                         ], list(plan))
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1125
1126
    def test_plan_lca_merge(self):
1127
        self.setup_plan_merge()
1128
        plan = self.plan_merge_vf.plan_lca_merge('B', 'C')
1129
        self.assertEqual([
1130
                          ('new-b', 'f\n'),
1131
                          ('unchanged', 'a\n'),
1132
                          ('killed-b', 'c\n'),
1133
                          ('new-a', 'e\n'),
1134
                          ('new-a', 'h\n'),
1135
                          ('killed-a', 'b\n'),
1136
                          ('unchanged', 'g\n')],
1137
                         list(plan))
1138
1139
    def test_plan_lca_merge_uncommitted_files(self):
1140
        self.setup_plan_merge_uncommitted()
1141
        plan = self.plan_merge_vf.plan_lca_merge('B:', 'C:')
1142
        self.assertEqual([
1143
                          ('new-b', 'f\n'),
1144
                          ('unchanged', 'a\n'),
1145
                          ('killed-b', 'c\n'),
1146
                          ('new-a', 'e\n'),
1147
                          ('new-a', 'h\n'),
1148
                          ('killed-a', 'b\n'),
1149
                          ('unchanged', 'g\n')],
1150
                         list(plan))
1151
1152
    def test_plan_lca_merge_with_base(self):
1153
        self.setup_merge_with_base()
1154
        plan = self.plan_merge_vf.plan_lca_merge('THIS', 'OTHER', 'BASE')
1155
        self.assertEqual([('unchanged', 'a\n'),
1156
                          ('new-b', 'f\n'),
1157
                          ('unchanged', 'b\n'),
1158
                          ('killed-b', 'c\n'),
1159
                          ('new-a', 'd\n')
1160
                         ], list(plan))
1161
1162
    def test_plan_lca_merge_with_criss_cross(self):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1163
        self.add_version(('root', 'ROOT'), [], 'abc')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1164
        # each side makes a change
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1165
        self.add_version(('root', 'REV1'), [('root', 'ROOT')], 'abcd')
1166
        self.add_version(('root', 'REV2'), [('root', 'ROOT')], 'abce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1167
        # both sides merge, discarding others' changes
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1168
        self.add_version(('root', 'LCA1'),
1169
            [('root', 'REV1'), ('root', 'REV2')], 'abcd')
1170
        self.add_version(('root', 'LCA2'),
1171
            [('root', 'REV1'), ('root', 'REV2')], 'fabce')
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1172
        plan = self.plan_merge_vf.plan_lca_merge('LCA1', 'LCA2')
3144.3.10 by Aaron Bentley
Use correct index when emitting conflicted-b
1173
        self.assertEqual([('new-b', 'f\n'),
1174
                          ('unchanged', 'a\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1175
                          ('unchanged', 'b\n'),
1176
                          ('unchanged', 'c\n'),
3144.3.3 by Aaron Bentley
Update test for new conflicted types
1177
                          ('conflicted-a', 'd\n'),
1178
                          ('conflicted-b', 'e\n'),
3144.3.1 by Aaron Bentley
Implement LCA merge, with problematic conflict markers
1179
                         ], list(plan))
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
1180
3287.17.1 by John Arbash Meinel
Fix bug #235715 by using the empty list as the text for a base of NULL_REVISION.
1181
    def test_plan_lca_merge_with_null(self):
3350.6.5 by Robert Collins
Update to bzr.dev.
1182
        self.add_version(('root', 'A'), [], 'ab')
1183
        self.add_version(('root', 'B'), [], 'bc')
3287.17.1 by John Arbash Meinel
Fix bug #235715 by using the empty list as the text for a base of NULL_REVISION.
1184
        plan = self.plan_merge_vf.plan_lca_merge('A', 'B')
1185
        self.assertEqual([('new-a', 'a\n'),
1186
                          ('unchanged', 'b\n'),
1187
                          ('new-b', 'c\n'),
1188
                         ], list(plan))
1189
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1190
    def test_plan_merge_with_delete_and_change(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
1191
        self.add_rev('root', 'C', [], 'a')
1192
        self.add_rev('root', 'A', ['C'], 'b')
1193
        self.add_rev('root', 'B', ['C'], '')
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1194
        plan = self.plan_merge_vf.plan_merge('A', 'B')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1195
        self.assertEqual([('killed-both', 'a\n'),
1196
                          ('new-a', 'b\n'),
1197
                         ], list(plan))
1198
1199
    def test_plan_merge_with_move_and_change(self):
3514.2.17 by John Arbash Meinel
On Ian's suggestion, change the 'plan_merge' tests to use the clearer 'add_rev' instead of 'add_version'
1200
        self.add_rev('root', 'C', [], 'abcd')
1201
        self.add_rev('root', 'A', ['C'], 'acbd')
1202
        self.add_rev('root', 'B', ['C'], 'aBcd')
3514.2.2 by John Arbash Meinel
Restore a real weave merge to 'bzr merge --weave'.
1203
        plan = self.plan_merge_vf.plan_merge('A', 'B')
1204
        self.assertEqual([('unchanged', 'a\n'),
1205
                          ('new-a', 'c\n'),
1206
                          ('killed-b', 'b\n'),
1207
                          ('new-b', 'B\n'),
1208
                          ('killed-a', 'c\n'),
1209
                          ('unchanged', 'd\n'),
3514.2.1 by Aaron Bentley
Test for correct conflicts on delete + change
1210
                         ], list(plan))
1211
3144.5.3 by Aaron Bentley
Test interesting_files for LCA merge
1212
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1213
class LoggingMerger(object):
1214
    # These seem to be the required attributes
1215
    requires_base = False
1216
    supports_reprocess = False
1217
    supports_show_base = False
1218
    supports_cherrypick = False
1219
    # We intentionally do not define supports_lca_trees
1220
1221
    def __init__(self, *args, **kwargs):
1222
        self.args = args
1223
        self.kwargs = kwargs
1224
1225
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1226
class TestMergerBase(TestCaseWithMemoryTransport):
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1227
    """Common functionality for Merger tests that don't write to disk."""
3514.4.1 by John Arbash Meinel
Update Merger to set a flag when we encounter a criss-cross merge.
1228
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1229
    def get_builder(self):
1230
        builder = self.make_branch_builder('path')
1231
        builder.start_series()
1232
        self.addCleanup(builder.finish_series)
1233
        return builder
1234
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1235
    def setup_simple_graph(self):
1236
        """Create a simple 3-node graph.
1237
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1238
        :return: A BranchBuilder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1239
        """
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1240
        #
1241
        #  A
1242
        #  |\
1243
        #  B C
1244
        #
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1245
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1246
        builder.build_snapshot(None,
1247
            [('add', ('', None, 'directory', None))],
1248
            revision_id='A-id' )
1249
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1250
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1251
        return builder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1252
1253
    def setup_criss_cross_graph(self):
1254
        """Create a 5-node graph with a criss-cross.
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1255
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1256
        :return: A BranchBuilder
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1257
        """
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1258
        # A
1259
        # |\
1260
        # B C
1261
        # |X|
1262
        # D E
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1263
        builder = self.setup_simple_graph()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1264
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1265
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1266
        return builder
1267
6885.5.8 by Jelmer Vernooij
Remove interesting_ids support from merge.
1268
    def make_Merger(self, builder, other_revision_id, interesting_files=None):
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1269
        """Make a Merger object from a branch builder"""
1270
        mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1271
        mem_tree.lock_write()
1272
        self.addCleanup(mem_tree.unlock)
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
1273
        merger = _mod_merge.Merger.from_revision_ids(
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1274
            mem_tree, other_revision_id)
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1275
        merger.set_interesting_files(interesting_files)
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1276
        merger.merge_type = _mod_merge.Merge3Merger
1277
        return merger
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1278
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1279
1280
class TestMergerInMemory(TestMergerBase):
1281
4595.13.2 by Alexander Belchenko
[cherrypick revno 4650 from bzr.dev] Fix shelve on windows. (Robert Collins, #305006)
1282
    def test_cache_trees_with_revision_ids_None(self):
1283
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1284
        original_cache = dict(merger._cached_trees)
1285
        merger.cache_trees_with_revision_ids([None])
1286
        self.assertEqual(original_cache, merger._cached_trees)
1287
1288
    def test_cache_trees_with_revision_ids_no_revision_id(self):
1289
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1290
        original_cache = dict(merger._cached_trees)
1291
        tree = self.make_branch_and_memory_tree('tree')
1292
        merger.cache_trees_with_revision_ids([tree])
1293
        self.assertEqual(original_cache, merger._cached_trees)
1294
1295
    def test_cache_trees_with_revision_ids_having_revision_id(self):
1296
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
1297
        original_cache = dict(merger._cached_trees)
1298
        tree = merger.this_branch.repository.revision_tree('B-id')
1299
        original_cache['B-id'] = tree
1300
        merger.cache_trees_with_revision_ids([tree])
1301
        self.assertEqual(original_cache, merger._cached_trees)
1302
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1303
    def test_find_base(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1304
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1305
        self.assertEqual('A-id', merger.base_rev_id)
1306
        self.assertFalse(merger._is_criss_cross)
1307
        self.assertIs(None, merger._lca_trees)
1308
1309
    def test_find_base_criss_cross(self):
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1310
        builder = self.setup_criss_cross_graph()
1311
        merger = self.make_Merger(builder, 'E-id')
3514.4.1 by John Arbash Meinel
Update Merger to set a flag when we encounter a criss-cross merge.
1312
        self.assertEqual('A-id', merger.base_rev_id)
1313
        self.assertTrue(merger._is_criss_cross)
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1314
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1315
                                            for t in merger._lca_trees])
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1316
        # If we swap the order, we should get a different lca order
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1317
        builder.build_snapshot(['E-id'], [], revision_id='F-id')
3514.4.14 by John Arbash Meinel
Add a test which shows that the ordering switches when you pick the other parent.
1318
        merger = self.make_Merger(builder, 'D-id')
1319
        self.assertEqual(['C-id', 'B-id'], [t.get_revision_id()
1320
                                            for t in merger._lca_trees])
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1321
3514.4.23 by John Arbash Meinel
Handle when there are more than 2 LCAs while searching for the unique lca.
1322
    def test_find_base_triple_criss_cross(self):
1323
        #       A-.
1324
        #      / \ \
1325
        #     B   C F # F is merged into both branches
1326
        #     |\ /| |
1327
        #     | X | |\
1328
        #     |/ \| | :
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1329
        #   : D   E |
1330
        #    \|   |/
3514.4.23 by John Arbash Meinel
Handle when there are more than 2 LCAs while searching for the unique lca.
1331
        #     G   H
1332
        builder = self.setup_criss_cross_graph()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1333
        builder.build_snapshot(['A-id'], [], revision_id='F-id')
1334
        builder.build_snapshot(['E-id', 'F-id'], [], revision_id='H-id')
1335
        builder.build_snapshot(['D-id', 'F-id'], [], revision_id='G-id')
3514.4.23 by John Arbash Meinel
Handle when there are more than 2 LCAs while searching for the unique lca.
1336
        merger = self.make_Merger(builder, 'H-id')
1337
        self.assertEqual(['B-id', 'C-id', 'F-id'],
1338
                         [t.get_revision_id() for t in merger._lca_trees])
1339
5540.1.2 by Gary van der Merwe
Add a test for bug #588698, for merging a new root more than once.
1340
    def test_find_base_new_root_criss_cross(self):
1341
        # A   B
1342
        # |\ /|
1343
        # | X |
1344
        # |/ \|
1345
        # C   D
1346
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1347
        builder.build_snapshot(None,
1348
            [('add', ('', None, 'directory', None))],
1349
            revision_id='A-id')
1350
        builder.build_snapshot([],
1351
            [('add', ('', None, 'directory', None))],
1352
            revision_id='B-id')
1353
        builder.build_snapshot(['A-id', 'B-id'], [], revision_id='D-id')
1354
        builder.build_snapshot(['A-id', 'B-id'], [], revision_id='C-id')
5540.1.2 by Gary van der Merwe
Add a test for bug #588698, for merging a new root more than once.
1355
        merger = self.make_Merger(builder, 'D-id')
1356
        self.assertEqual('A-id', merger.base_rev_id)
1357
        self.assertTrue(merger._is_criss_cross)
1358
        self.assertEqual(['A-id', 'B-id'], [t.get_revision_id()
1359
                                            for t in merger._lca_trees])
1360
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1361
    def test_no_criss_cross_passed_to_merge_type(self):
1362
        class LCATreesMerger(LoggingMerger):
1363
            supports_lca_trees = True
1364
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1365
        merger = self.make_Merger(self.setup_simple_graph(), 'C-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1366
        merger.merge_type = LCATreesMerger
1367
        merge_obj = merger.make_merger()
1368
        self.assertIsInstance(merge_obj, LCATreesMerger)
1369
        self.assertFalse('lca_trees' in merge_obj.kwargs)
1370
1371
    def test_criss_cross_passed_to_merge_type(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1372
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1373
        merger.merge_type = _mod_merge.Merge3Merger
1374
        merge_obj = merger.make_merger()
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1375
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1376
                                            for t in merger._lca_trees])
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1377
1378
    def test_criss_cross_not_supported_merge_type(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1379
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1380
        # We explicitly do not define supports_lca_trees
1381
        merger.merge_type = LoggingMerger
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1382
        merge_obj = merger.make_merger()
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1383
        self.assertIsInstance(merge_obj, LoggingMerger)
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1384
        self.assertFalse('lca_trees' in merge_obj.kwargs)
1385
1386
    def test_criss_cross_unsupported_merge_type(self):
1387
        class UnsupportedLCATreesMerger(LoggingMerger):
1388
            supports_lca_trees = False
1389
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1390
        merger = self.make_Merger(self.setup_criss_cross_graph(), 'E-id')
3514.4.4 by John Arbash Meinel
Test that the lca_trees are passed down to the Merger object when appropriate.
1391
        merger.merge_type = UnsupportedLCATreesMerger
1392
        merge_obj = merger.make_merger()
1393
        self.assertIsInstance(merge_obj, UnsupportedLCATreesMerger)
1394
        self.assertFalse('lca_trees' in merge_obj.kwargs)
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1395
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1396
1397
class TestMergerEntriesLCA(TestMergerBase):
1398
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
1399
    def make_merge_obj(self, builder, other_revision_id,
6885.5.8 by Jelmer Vernooij
Remove interesting_ids support from merge.
1400
                       interesting_files=None):
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
1401
        merger = self.make_Merger(builder, other_revision_id,
6885.5.8 by Jelmer Vernooij
Remove interesting_ids support from merge.
1402
            interesting_files=interesting_files)
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1403
        return merger.make_merger()
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1404
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1405
    def test_simple(self):
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1406
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1407
        builder.build_snapshot(None,
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1408
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1409
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1410
            revision_id='A-id')
1411
        builder.build_snapshot(['A-id'],
1412
            [('modify', ('a-id', 'a\nb\nC\nc\n'))],
1413
            revision_id='C-id')
1414
        builder.build_snapshot(['A-id'],
1415
            [('modify', ('a-id', 'a\nB\nb\nc\n'))],
1416
            revision_id='B-id')
1417
        builder.build_snapshot(['C-id', 'B-id'],
1418
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))],
1419
            revision_id='E-id')
1420
        builder.build_snapshot(['B-id', 'C-id'],
1421
            [('modify', ('a-id', 'a\nB\nb\nC\nc\n'))],
1422
            revision_id='D-id', )
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1423
        merge_obj = self.make_merge_obj(builder, 'E-id')
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1424
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1425
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1426
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1427
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1428
        entries = list(merge_obj._entries_lca())
1429
1430
        # (file_id, changed, parents, names, executable)
1431
        # BASE, lca1, lca2, OTHER, THIS
3514.4.7 by John Arbash Meinel
switch over test_merge to using the new BranchBuilder api.
1432
        root_id = 'a-root-id'
3514.4.12 by John Arbash Meinel
add more filtering for when a directory hasn't actually changed.
1433
        self.assertEqual([('a-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1434
                           ((u'a', [u'a', u'a']), u'a', u'a'),
3514.4.5 by John Arbash Meinel
Initial work on _entries_lca.
1435
                           ((root_id, [root_id, root_id]), root_id, root_id),
1436
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1437
                           ((False, [False, False]), False, False)),
1438
                         ], entries)
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1439
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1440
    def test_not_in_base(self):
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1441
        # LCAs all have the same last-modified revision for the file, as do
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1442
        # the tips, but the base has something different
1443
        #       A    base, doesn't have the file
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1444
        #       |\
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1445
        #       B C  B introduces 'foo', C introduces 'bar'
1446
        #       |X|
1447
        #       D E  D and E now both have 'foo' and 'bar'
1448
        #       |X|
1449
        #       F G  the files are now in F, G, D and E, but not in A
1450
        #            G modifies 'bar'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1451
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1452
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1453
        builder.build_snapshot(None,
1454
            [('add', (u'', 'a-root-id', 'directory', None))],
1455
            revision_id='A-id')
1456
        builder.build_snapshot(['A-id'],
1457
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
1458
            revision_id='B-id')
1459
        builder.build_snapshot(['A-id'],
1460
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))],
1461
            revision_id='C-id')
1462
        builder.build_snapshot(['B-id', 'C-id'],
1463
            [('add', (u'bar', 'bar-id', 'file', 'd\ne\nf\n'))],
1464
            revision_id='D-id')
1465
        builder.build_snapshot(['C-id', 'B-id'],
1466
            [('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
1467
            revision_id='E-id')
1468
        builder.build_snapshot(['E-id', 'D-id'],
1469
            [('modify', (u'bar-id', 'd\ne\nf\nG\n'))],
1470
            revision_id='G-id')
1471
        builder.build_snapshot(['D-id', 'E-id'], [], revision_id='F-id')
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1472
        merge_obj = self.make_merge_obj(builder, 'G-id')
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1473
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1474
        self.assertEqual(['D-id', 'E-id'], [t.get_revision_id()
1475
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1476
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1477
        entries = list(merge_obj._entries_lca())
1478
        root_id = 'a-root-id'
1479
        self.assertEqual([('bar-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1480
                           ((None, [u'bar', u'bar']), u'bar', u'bar'),
3514.4.10 by John Arbash Meinel
Test the case where BASE is missing a file that is present in THIS, OTHER and all LCAs.
1481
                           ((None, [root_id, root_id]), root_id, root_id),
1482
                           ((None, [u'bar', u'bar']), u'bar', u'bar'),
1483
                           ((None, [False, False]), False, False)),
1484
                         ], entries)
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1485
1486
    def test_not_in_this(self):
1487
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1488
        builder.build_snapshot(None,
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1489
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1490
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1491
            revision_id='A-id')
1492
        builder.build_snapshot(['A-id'],
1493
            [('modify', ('a-id', 'a\nB\nb\nc\n'))],
1494
            revision_id='B-id')
1495
        builder.build_snapshot(['A-id'],
1496
            [('modify', ('a-id', 'a\nb\nC\nc\n'))],
1497
            revision_id='C-id')
1498
        builder.build_snapshot(['C-id', 'B-id'],
1499
            [('modify', ('a-id', 'a\nB\nb\nC\nc\nE\n'))],
1500
            revision_id='E-id')
1501
        builder.build_snapshot(['B-id', 'C-id'],
1502
            [('unversion', 'a-id')],
1503
            revision_id='D-id')
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1504
        merge_obj = self.make_merge_obj(builder, 'E-id')
1505
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1506
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1507
                                            for t in merge_obj._lca_trees])
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1508
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
1509
1510
        entries = list(merge_obj._entries_lca())
1511
        root_id = 'a-root-id'
1512
        self.assertEqual([('a-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1513
                           ((u'a', [u'a', u'a']), u'a', None),
3514.4.11 by John Arbash Meinel
Handle when an entry is missing in THIS
1514
                           ((root_id, [root_id, root_id]), root_id, None),
1515
                           ((u'a', [u'a', u'a']), u'a', None),
1516
                           ((False, [False, False]), False, None)),
1517
                         ], entries)
1518
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1519
    def test_file_not_in_one_lca(self):
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1520
        #   A   # just root
1521
        #   |\
1522
        #   B C # B no file, C introduces a file
1523
        #   |X|
1524
        #   D E # D and E both have the file, unchanged from C
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1525
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1526
        builder.build_snapshot(None,
1527
            [('add', (u'', 'a-root-id', 'directory', None))],
1528
            revision_id='A-id')
1529
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1530
        builder.build_snapshot(['A-id'],
1531
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1532
            revision_id='C-id')
1533
        builder.build_snapshot(['C-id', 'B-id'],
1534
                               [], revision_id='E-id') # Inherited from C
1535
        builder.build_snapshot(['B-id', 'C-id'], # Merged from C
1536
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1537
            revision_id='D-id')
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1538
        merge_obj = self.make_merge_obj(builder, 'E-id')
1539
1540
        self.assertEqual(['B-id', 'C-id'], [t.get_revision_id()
1541
                                            for t in merge_obj._lca_trees])
1542
        self.assertEqual('A-id', merge_obj.base_tree.get_revision_id())
1543
1544
        entries = list(merge_obj._entries_lca())
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1545
        self.assertEqual([], entries)
3514.4.13 by John Arbash Meinel
Switch the lca_trees to be in 'find_merge_order'.
1546
3514.4.15 by John Arbash Meinel
Handle when OTHER doesn't have the entry.
1547
    def test_not_in_other(self):
1548
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1549
        builder.build_snapshot(None,
3514.4.15 by John Arbash Meinel
Handle when OTHER doesn't have the entry.
1550
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1551
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1552
            revision_id='A-id')
1553
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1554
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1555
        builder.build_snapshot(
1556
                ['C-id', 'B-id'],
1557
                [('unversion', 'a-id')], revision_id='E-id')
1558
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.15 by John Arbash Meinel
Handle when OTHER doesn't have the entry.
1559
        merge_obj = self.make_merge_obj(builder, 'E-id')
1560
1561
        entries = list(merge_obj._entries_lca())
1562
        root_id = 'a-root-id'
1563
        self.assertEqual([('a-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1564
                           ((u'a', [u'a', u'a']), None, u'a'),
3514.4.15 by John Arbash Meinel
Handle when OTHER doesn't have the entry.
1565
                           ((root_id, [root_id, root_id]), None, root_id),
1566
                           ((u'a', [u'a', u'a']), None, u'a'),
1567
                           ((False, [False, False]), None, False)),
1568
                         ], entries)
1569
3514.4.30 by John Arbash Meinel
Several updates.
1570
    def test_not_in_other_or_lca(self):
1571
        #       A    base, introduces 'foo'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1572
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
1573
        #       B C  B nothing, C deletes foo
1574
        #       |X|
1575
        #       D E  D restores foo (same as B), E leaves it deleted
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1576
        # Analysis:
1577
        #   A => B, no changes
1578
        #   A => C, delete foo (C should supersede B)
1579
        #   C => D, restore foo
1580
        #   C => E, no changes
1581
        # D would then win 'cleanly' and no record would be given
3514.4.30 by John Arbash Meinel
Several updates.
1582
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1583
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
1584
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1585
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))],
1586
            revision_id='A-id')
1587
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1588
        builder.build_snapshot(['A-id'],
1589
            [('unversion', 'foo-id')], revision_id='C-id')
1590
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1591
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.30 by John Arbash Meinel
Several updates.
1592
        merge_obj = self.make_merge_obj(builder, 'E-id')
1593
1594
        entries = list(merge_obj._entries_lca())
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1595
        self.assertEqual([], entries)
1596
1597
    def test_not_in_other_mod_in_lca1_not_in_lca2(self):
1598
        #       A    base, introduces 'foo'
1599
        #       |\
1600
        #       B C  B changes 'foo', C deletes foo
1601
        #       |X|
1602
        #       D E  D restores foo (same as B), E leaves it deleted (as C)
1603
        # Analysis:
1604
        #   A => B, modified foo
1605
        #   A => C, delete foo, C does not supersede B
1606
        #   B => D, no changes
1607
        #   C => D, resolve in favor of B
1608
        #   B => E, resolve in favor of E
1609
        #   C => E, no changes
1610
        # In this case, we have a conflict of how the changes were resolved. E
1611
        # picked C and D picked B, so we should issue a conflict
1612
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1613
        builder.build_snapshot(None,
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1614
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1615
             ('add', (u'foo', 'foo-id', 'file', 'content\n'))],
1616
            revision_id='A-id')
1617
        builder.build_snapshot(['A-id'], [
1618
            ('modify', ('foo-id', 'new-content\n'))],
1619
            revision_id='B-id')
1620
        builder.build_snapshot(['A-id'],
1621
            [('unversion', 'foo-id')],
1622
            revision_id='C-id')
1623
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1624
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1625
        merge_obj = self.make_merge_obj(builder, 'E-id')
1626
1627
        entries = list(merge_obj._entries_lca())
3948.1.4 by Vincent Ladeuil
More cleanup and fix overzealous previous one.
1628
        root_id = 'a-root-id'
3514.4.30 by John Arbash Meinel
Several updates.
1629
        self.assertEqual([('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1630
                           ((u'foo', [u'foo', None]), None, u'foo'),
3514.4.30 by John Arbash Meinel
Several updates.
1631
                           ((root_id, [root_id, None]), None, root_id),
1632
                           ((u'foo', [u'foo', None]), None, 'foo'),
1633
                           ((False, [False, None]), None, False)),
1634
                         ], entries)
1635
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1636
    def test_only_in_one_lca(self):
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1637
        #   A   add only root
1638
        #   |\
1639
        #   B C B nothing, C add file
1640
        #   |X|
1641
        #   D E D still has nothing, E removes file
1642
        # Analysis:
1643
        #   B => D, no change
1644
        #   C => D, removed the file
1645
        #   B => E, no change
1646
        #   C => E, removed the file
1647
        # Thus D & E have identical changes, and this is a no-op
1648
        # Alternatively:
1649
        #   A => B, no change
1650
        #   A => C, add file, thus C supersedes B
1651
        #   w/ C=BASE, D=THIS, E=OTHER we have 'happy convergence'
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1652
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1653
        builder.build_snapshot(None,
1654
            [('add', (u'', 'a-root-id', 'directory', None))],
1655
            revision_id='A-id')
1656
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1657
        builder.build_snapshot(['A-id'],
1658
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1659
            revision_id='C-id')
1660
        builder.build_snapshot(['C-id', 'B-id'],
1661
            [('unversion', 'a-id')],
1662
            revision_id='E-id')
1663
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1664
        merge_obj = self.make_merge_obj(builder, 'E-id')
1665
1666
        entries = list(merge_obj._entries_lca())
3948.1.1 by John Arbash Meinel
Fix an edge case with deleted files and criss-cross merges.
1667
        self.assertEqual([], entries)
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1668
3514.4.16 by John Arbash Meinel
another test for only in OTHER
1669
    def test_only_in_other(self):
1670
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1671
        builder.build_snapshot(None,
1672
            [('add', (u'', 'a-root-id', 'directory', None))],
1673
            revision_id='A-id')
1674
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
1675
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1676
        builder.build_snapshot(['C-id', 'B-id'],
1677
            [('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
1678
            revision_id='E-id')
1679
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.16 by John Arbash Meinel
another test for only in OTHER
1680
        merge_obj = self.make_merge_obj(builder, 'E-id')
1681
1682
        entries = list(merge_obj._entries_lca())
1683
        root_id = 'a-root-id'
1684
        self.assertEqual([('a-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1685
                           ((None, [None, None]), u'a', None),
3514.4.16 by John Arbash Meinel
another test for only in OTHER
1686
                           ((None, [None, None]), root_id, None),
1687
                           ((None, [None, None]), u'a', None),
1688
                           ((None, [None, None]), False, None)),
1689
                         ], entries)
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
1690
3514.4.30 by John Arbash Meinel
Several updates.
1691
    def test_one_lca_supersedes(self):
3514.4.41 by John Arbash Meinel
Some grammar and other clarity feedback from Aaron.
1692
        # One LCA supersedes the other LCAs last modified value, but the
3514.4.30 by John Arbash Meinel
Several updates.
1693
        # value is not the same as BASE.
1694
        #       A    base, introduces 'foo', last mod A
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1695
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
1696
        #       B C  B modifies 'foo' (mod B), C does nothing (mod A)
1697
        #       |X|
1698
        #       D E  D does nothing (mod B), E updates 'foo' (mod E)
1699
        #       |X|
1700
        #       F G  F updates 'foo' (mod F). G does nothing (mod E)
1701
        #
1702
        #   At this point, G should not be considered to modify 'foo', even
1703
        #   though its LCAs disagree. This is because the modification in E
1704
        #   completely supersedes the value in D.
1705
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1706
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
1707
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1708
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1709
            revision_id='A-id')
1710
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1711
        builder.build_snapshot(['A-id'],
1712
            [('modify', ('foo-id', 'B content\n'))],
1713
            revision_id='B-id')
1714
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1715
        builder.build_snapshot(['C-id', 'B-id'],
1716
            [('modify', ('foo-id', 'E content\n'))],
1717
            revision_id='E-id')
1718
        builder.build_snapshot(['E-id', 'D-id'], [], revision_id='G-id')
1719
        builder.build_snapshot(['D-id', 'E-id'],
1720
            [('modify', ('foo-id', 'F content\n'))],
1721
            revision_id='F-id')
3514.4.30 by John Arbash Meinel
Several updates.
1722
        merge_obj = self.make_merge_obj(builder, 'G-id')
1723
1724
        self.assertEqual([], list(merge_obj._entries_lca()))
1725
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
1726
    def test_one_lca_supersedes_path(self):
1727
        # Double-criss-cross merge, the ultimate base value is different from
1728
        # the intermediate.
1729
        #   A    value 'foo'
1730
        #   |\
1731
        #   B C  B value 'bar', C = 'foo'
1732
        #   |X|
1733
        #   D E  D = 'bar', E supersedes to 'bing'
1734
        #   |X|
1735
        #   F G  F = 'bing', G supersedes to 'barry'
1736
        #
1737
        # In this case, we technically should not care about the value 'bar' for
1738
        # D, because it was clearly superseded by E's 'bing'. The
1739
        # per-file/attribute graph would actually look like:
1740
        #   A
1741
        #   |
1742
        #   B
1743
        #   |
1744
        #   E
1745
        #   |
1746
        #   G
1747
        #
1748
        # Because the other side of the merge never modifies the value, it just
1749
        # takes the value from the merge.
1750
        #
1751
        # ATM this fails because we will prune 'foo' from the LCAs, but we
1752
        # won't prune 'bar'. This is getting far off into edge-case land, so we
1753
        # aren't supporting it yet.
1754
        #
1755
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1756
        builder.build_snapshot(None,
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
1757
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1758
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1759
            revision_id='A-id')
1760
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1761
        builder.build_snapshot(['A-id'],
1762
            [('rename', ('foo', 'bar'))],
1763
            revision_id='B-id')
1764
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1765
        builder.build_snapshot(['C-id', 'B-id'],
1766
            [('rename', ('foo', 'bing'))],
1767
            revision_id='E-id') # override to bing
1768
        builder.build_snapshot(['E-id', 'D-id'],
1769
            [('rename', ('bing', 'barry'))],
1770
            revision_id='G-id') # override to barry
1771
        builder.build_snapshot(['D-id', 'E-id'],
1772
            [('rename', ('bar', 'bing'))],
1773
            revision_id='F-id') # Merge in E's change
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
1774
        merge_obj = self.make_merge_obj(builder, 'G-id')
1775
1776
        self.expectFailure("We don't do an actual heads() check on lca values,"
1777
            " or use the per-attribute graph",
1778
            self.assertEqual, [], list(merge_obj._entries_lca()))
1779
1780
    def test_one_lca_accidentally_pruned(self):
1781
        # Another incorrect resolution from the same basic flaw:
1782
        #   A    value 'foo'
1783
        #   |\
1784
        #   B C  B value 'bar', C = 'foo'
1785
        #   |X|
1786
        #   D E  D = 'bar', E reverts to 'foo'
1787
        #   |X|
1788
        #   F G  F = 'bing', G switches to 'bar'
1789
        #
1790
        # 'bar' will not be seen as an interesting change, because 'foo' will
1791
        # be pruned from the LCAs, even though it was newly introduced by E
1792
        # (superseding B).
1793
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1794
        builder.build_snapshot(None,
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
1795
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1796
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1797
            revision_id='A-id')
1798
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1799
        builder.build_snapshot(['A-id'],
1800
            [('rename', ('foo', 'bar'))],
1801
            revision_id='B-id')
1802
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1803
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1804
        builder.build_snapshot(['E-id', 'D-id'],
1805
            [('rename', ('foo', 'bar'))],
1806
            revision_id='G-id')
1807
        builder.build_snapshot(['D-id', 'E-id'],
1808
            [('rename', ('bar', 'bing'))],
1809
            revision_id='F-id') # should end up conflicting
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
1810
        merge_obj = self.make_merge_obj(builder, 'G-id')
1811
1812
        entries = list(merge_obj._entries_lca())
1813
        root_id = 'a-root-id'
1814
        self.expectFailure("We prune values from BASE even when relevant.",
1815
            self.assertEqual,
1816
                [('foo-id', False,
1817
                  ((root_id, [root_id, root_id]), root_id, root_id),
1818
                  ((u'foo', [u'bar', u'foo']), u'bar', u'bing'),
1819
                  ((False, [False, False]), False, False)),
1820
                ], entries)
1821
3514.4.30 by John Arbash Meinel
Several updates.
1822
    def test_both_sides_revert(self):
1823
        # Both sides of a criss-cross revert the text to the lca
1824
        #       A    base, introduces 'foo'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1825
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
1826
        #       B C  B modifies 'foo', C modifies 'foo'
1827
        #       |X|
1828
        #       D E  D reverts to B, E reverts to C
1829
        # This should conflict
1830
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1831
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
1832
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1833
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1834
            revision_id='A-id')
1835
        builder.build_snapshot(['A-id'],
1836
            [('modify', ('foo-id', 'B content\n'))],
1837
            revision_id='B-id')
1838
        builder.build_snapshot(['A-id'],
1839
            [('modify', ('foo-id', 'C content\n'))],
1840
            revision_id='C-id')
1841
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1842
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.30 by John Arbash Meinel
Several updates.
1843
        merge_obj = self.make_merge_obj(builder, 'E-id')
1844
1845
        entries = list(merge_obj._entries_lca())
1846
        root_id = 'a-root-id'
1847
        self.assertEqual([('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1848
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
3514.4.30 by John Arbash Meinel
Several updates.
1849
                           ((root_id, [root_id, root_id]), root_id, root_id),
1850
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1851
                           ((False, [False, False]), False, False)),
1852
                         ], entries)
1853
1854
    def test_different_lca_resolve_one_side_updates_content(self):
1855
        # Both sides converge, but then one side updates the text.
1856
        #       A    base, introduces 'foo'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1857
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
1858
        #       B C  B modifies 'foo', C modifies 'foo'
1859
        #       |X|
1860
        #       D E  D reverts to B, E reverts to C
1861
        #       |
1862
        #       F    F updates to a new value
1863
        # We need to emit an entry for 'foo', because D & E differed on the
1864
        # merge resolution
1865
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1866
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
1867
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1868
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1869
            revision_id='A-id')
1870
        builder.build_snapshot(['A-id'],
1871
            [('modify', ('foo-id', 'B content\n'))],
1872
            revision_id='B-id')
1873
        builder.build_snapshot(['A-id'],
1874
            [('modify', ('foo-id', 'C content\n'))],
1875
            revision_id='C-id', )
1876
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1877
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1878
        builder.build_snapshot(['D-id'],
1879
            [('modify', ('foo-id', 'F content\n'))],
1880
            revision_id='F-id')
3514.4.30 by John Arbash Meinel
Several updates.
1881
        merge_obj = self.make_merge_obj(builder, 'E-id')
1882
1883
        entries = list(merge_obj._entries_lca())
1884
        root_id = 'a-root-id'
1885
        self.assertEqual([('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1886
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
3514.4.30 by John Arbash Meinel
Several updates.
1887
                           ((root_id, [root_id, root_id]), root_id, root_id),
1888
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1889
                           ((False, [False, False]), False, False)),
1890
                         ], entries)
1891
1892
    def test_same_lca_resolution_one_side_updates_content(self):
1893
        # Both sides converge, but then one side updates the text.
1894
        #       A    base, introduces 'foo'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
1895
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
1896
        #       B C  B modifies 'foo', C modifies 'foo'
1897
        #       |X|
1898
        #       D E  D and E use C's value
1899
        #       |
1900
        #       F    F updates to a new value
1901
        # I think it is a bug that this conflicts, but we don't have a way to
1902
        # detect otherwise. And because of:
1903
        #   test_different_lca_resolve_one_side_updates_content
1904
        # We need to conflict.
1905
1906
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1907
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
1908
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1909
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
1910
            revision_id='A-id')
1911
        builder.build_snapshot(['A-id'],
1912
            [('modify', ('foo-id', 'B content\n'))],
1913
            revision_id='B-id')
1914
        builder.build_snapshot(['A-id'],
1915
            [('modify', ('foo-id', 'C content\n'))],
1916
            revision_id='C-id')
1917
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1918
        builder.build_snapshot(['B-id', 'C-id'],
1919
            [('modify', ('foo-id', 'C content\n'))],
1920
            revision_id='D-id') # Same as E
1921
        builder.build_snapshot(['D-id'],
1922
            [('modify', ('foo-id', 'F content\n'))],
1923
            revision_id='F-id')
3514.4.30 by John Arbash Meinel
Several updates.
1924
        merge_obj = self.make_merge_obj(builder, 'E-id')
1925
1926
        entries = list(merge_obj._entries_lca())
1927
        self.expectFailure("We don't detect that LCA resolution was the"
1928
                           " same on both sides",
1929
            self.assertEqual, [], entries)
1930
3514.4.20 by John Arbash Meinel
Use the _lca_multi_way to work out if there is actually a kind/parent/name/content change.
1931
    def test_only_path_changed(self):
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
1932
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1933
        builder.build_snapshot(None,
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
1934
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1935
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1936
            revision_id='A-id')
1937
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1938
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1939
        builder.build_snapshot(['C-id', 'B-id'],
1940
            [('rename', (u'a', u'b'))],
1941
            revision_id='E-id')
1942
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
1943
        merge_obj = self.make_merge_obj(builder, 'E-id')
1944
        entries = list(merge_obj._entries_lca())
1945
        root_id = 'a-root-id'
1946
        # The content was not changed, only the path
1947
        self.assertEqual([('a-id', False,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1948
                           ((u'a', [u'b', u'b']), u'b', u'a'),
3514.4.19 by John Arbash Meinel
Add the _lca_multi_way function, and explicit tests.
1949
                           ((root_id, [root_id, root_id]), root_id, root_id),
1950
                           ((u'a', [u'a', u'a']), u'b', u'a'),
1951
                           ((False, [False, False]), False, False)),
1952
                         ], entries)
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
1953
1954
    def test_kind_changed(self):
1955
        # Identical content, except 'D' changes a-id into a directory
1956
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1957
        builder.build_snapshot(None,
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
1958
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1959
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1960
            revision_id='A-id')
1961
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1962
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1963
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
1964
            [('unversion', 'a-id'),
6008.2.5 by Andrew Bennetts
Rename 'checkpoint' to 'flush', add some unit tests and more comments.
1965
             ('flush', None),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1966
             ('add', (u'a', 'a-id', 'directory', None))],
1967
            revision_id='E-id')
1968
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
1969
        merge_obj = self.make_merge_obj(builder, 'E-id')
1970
        entries = list(merge_obj._entries_lca())
1971
        root_id = 'a-root-id'
1972
        # Only the kind was changed (content)
1973
        self.assertEqual([('a-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
1974
                           ((u'a', [u'a', u'a']), u'a', u'a'),
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
1975
                           ((root_id, [root_id, root_id]), root_id, root_id),
1976
                           ((u'a', [u'a', u'a']), u'a', u'a'),
1977
                           ((False, [False, False]), False, False)),
1978
                         ], entries)
1979
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
1980
    def test_this_changed_kind(self):
1981
        # Identical content, but THIS changes a file to a directory
1982
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1983
        builder.build_snapshot(None,
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
1984
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1985
             ('add', (u'a', 'a-id', 'file', 'content\n'))],
1986
            revision_id='A-id')
1987
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
1988
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
1989
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
1990
        builder.build_snapshot(['B-id', 'C-id'],
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
1991
            [('unversion', 'a-id'),
6008.2.5 by Andrew Bennetts
Rename 'checkpoint' to 'flush', add some unit tests and more comments.
1992
             ('flush', None),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1993
             ('add', (u'a', 'a-id', 'directory', None))],
1994
            revision_id='D-id')
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
1995
        merge_obj = self.make_merge_obj(builder, 'E-id')
1996
        entries = list(merge_obj._entries_lca())
1997
        # Only the kind was changed (content)
1998
        self.assertEqual([], entries)
1999
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2000
    def test_interesting_files(self):
2001
        # Two files modified, but we should filter one of them
2002
        builder = self.get_builder()
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
2003
        builder.build_snapshot(None,
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2004
            [('add', (u'', 'a-root-id', 'directory', None)),
2005
             ('add', (u'a', 'a-id', 'file', 'content\n')),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
2006
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2007
            revision_id='A-id')
2008
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2009
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2010
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2011
            [('modify', ('a-id', 'new-content\n')),
6816.2.2 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
2012
             ('modify', ('b-id', 'new-content\n'))],
2013
            revision_id='E-id')
2014
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2015
        merge_obj = self.make_merge_obj(builder, 'E-id',
2016
                                        interesting_files=['b'])
2017
        entries = list(merge_obj._entries_lca())
2018
        root_id = 'a-root-id'
2019
        self.assertEqual([('b-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2020
                           ((u'b', [u'b', u'b']), u'b', u'b'),
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2021
                           ((root_id, [root_id, root_id]), root_id, root_id),
2022
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2023
                           ((False, [False, False]), False, False)),
2024
                         ], entries)
2025
2026
    def test_interesting_file_in_this(self):
2027
        # This renamed the file, but it should still match the entry in other
2028
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2029
        builder.build_snapshot(None,
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2030
            [('add', (u'', 'a-root-id', 'directory', None)),
2031
             ('add', (u'a', 'a-id', 'file', 'content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2032
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2033
            revision_id='A-id')
2034
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2035
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2036
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2037
            [('modify', ('a-id', 'new-content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2038
             ('modify', ('b-id', 'new-content\n'))],
2039
            revision_id='E-id')
2040
        builder.build_snapshot(['B-id', 'C-id'],
2041
            [('rename', ('b', 'c'))],
2042
            revision_id='D-id')
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2043
        merge_obj = self.make_merge_obj(builder, 'E-id',
2044
                                        interesting_files=['c'])
2045
        entries = list(merge_obj._entries_lca())
2046
        root_id = 'a-root-id'
2047
        self.assertEqual([('b-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2048
                           ((u'b', [u'b', u'b']), u'b', u'c'),
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2049
                           ((root_id, [root_id, root_id]), root_id, root_id),
2050
                           ((u'b', [u'b', u'b']), u'b', u'c'),
2051
                           ((False, [False, False]), False, False)),
2052
                         ], entries)
2053
2054
    def test_interesting_file_in_base(self):
2055
        # This renamed the file, but it should still match the entry in BASE
2056
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2057
        builder.build_snapshot(None,
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2058
            [('add', (u'', 'a-root-id', 'directory', None)),
2059
             ('add', (u'a', 'a-id', 'file', 'content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2060
             ('add', (u'c', 'c-id', 'file', 'content\n'))],
2061
            revision_id='A-id')
2062
        builder.build_snapshot(['A-id'],
2063
            [('rename', ('c', 'b'))],
2064
            revision_id='B-id')
2065
        builder.build_snapshot(['A-id'],
2066
            [('rename', ('c', 'b'))],
2067
            revision_id='C-id')
2068
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2069
            [('modify', ('a-id', 'new-content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2070
             ('modify', ('c-id', 'new-content\n'))],
2071
            revision_id='E-id')
2072
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2073
        merge_obj = self.make_merge_obj(builder, 'E-id',
2074
                                        interesting_files=['c'])
2075
        entries = list(merge_obj._entries_lca())
2076
        root_id = 'a-root-id'
2077
        self.assertEqual([('c-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2078
                           ((u'c', [u'b', u'b']), u'b', u'b'),
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2079
                           ((root_id, [root_id, root_id]), root_id, root_id),
2080
                           ((u'c', [u'b', u'b']), u'b', u'b'),
2081
                           ((False, [False, False]), False, False)),
2082
                         ], entries)
2083
2084
    def test_interesting_file_in_lca(self):
2085
        # This renamed the file, but it should still match the entry in LCA
2086
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2087
        builder.build_snapshot(None,
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2088
            [('add', (u'', 'a-root-id', 'directory', None)),
2089
             ('add', (u'a', 'a-id', 'file', 'content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2090
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2091
            revision_id='A-id')
2092
        builder.build_snapshot(['A-id'],
2093
            [('rename', ('b', 'c'))], revision_id='B-id')
2094
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2095
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2096
            [('modify', ('a-id', 'new-content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2097
             ('modify', ('b-id', 'new-content\n'))],
2098
            revision_id='E-id')
2099
        builder.build_snapshot(['B-id', 'C-id'],
2100
            [('rename', ('c', 'b'))], revision_id='D-id')
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2101
        merge_obj = self.make_merge_obj(builder, 'E-id',
2102
                                        interesting_files=['c'])
2103
        entries = list(merge_obj._entries_lca())
2104
        root_id = 'a-root-id'
2105
        self.assertEqual([('b-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2106
                           ((u'b', [u'b', u'b']), u'b', u'b'),
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2107
                           ((root_id, [root_id, root_id]), root_id, root_id),
2108
                           ((u'b', [u'c', u'b']), u'b', u'b'),
2109
                           ((False, [False, False]), False, False)),
2110
                         ], entries)
2111
6885.5.8 by Jelmer Vernooij
Remove interesting_ids support from merge.
2112
    def test_interesting_files(self):
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2113
        # Two files modified, but we should filter one of them
2114
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2115
        builder.build_snapshot(None,
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2116
            [('add', (u'', 'a-root-id', 'directory', None)),
2117
             ('add', (u'a', 'a-id', 'file', 'content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2118
             ('add', (u'b', 'b-id', 'file', 'content\n'))],
2119
            revision_id='A-id')
2120
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2121
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2122
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2123
            [('modify', ('a-id', 'new-content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2124
             ('modify', ('b-id', 'new-content\n'))], revision_id='E-id')
2125
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2126
        merge_obj = self.make_merge_obj(builder, 'E-id',
6885.5.8 by Jelmer Vernooij
Remove interesting_ids support from merge.
2127
                                        interesting_files=['b'])
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2128
        entries = list(merge_obj._entries_lca())
2129
        root_id = 'a-root-id'
2130
        self.assertEqual([('b-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2131
                           ((u'b', [u'b', u'b']), u'b', u'b'),
3514.4.24 by John Arbash Meinel
Implement support for 'interesting_files' and 'interesting_ids' for _entries_lca
2132
                           ((root_id, [root_id, root_id]), root_id, root_id),
2133
                           ((u'b', [u'b', u'b']), u'b', u'b'),
2134
                           ((False, [False, False]), False, False)),
2135
                         ], entries)
2136
2137
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2138
2139
class TestMergerEntriesLCAOnDisk(tests.TestCaseWithTransport):
2140
2141
    def get_builder(self):
2142
        builder = self.make_branch_builder('path')
2143
        builder.start_series()
2144
        self.addCleanup(builder.finish_series)
2145
        return builder
2146
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2147
    def get_wt_from_builder(self, builder):
2148
        """Get a real WorkingTree from the builder."""
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2149
        the_branch = builder.get_branch()
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2150
        wt = the_branch.controldir.create_workingtree()
3514.4.31 by John Arbash Meinel
Add expected failures for cases where we should be looking at more than
2151
        # Note: This is a little bit ugly, but we are holding the branch
2152
        #       write-locked as part of the build process, and we would like to
2153
        #       maintain that. So we just force the WT to re-use the same
2154
        #       branch object.
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2155
        wt._branch = the_branch
2156
        wt.lock_write()
2157
        self.addCleanup(wt.unlock)
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2158
        return wt
2159
2160
    def do_merge(self, builder, other_revision_id):
2161
        wt = self.get_wt_from_builder(builder)
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2162
        merger = _mod_merge.Merger.from_revision_ids(
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2163
            wt, other_revision_id)
2164
        merger.merge_type = _mod_merge.Merge3Merger
2165
        return wt, merger.do_merge()
2166
2167
    def test_simple_lca(self):
2168
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2169
        builder.build_snapshot(None,
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2170
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2171
             ('add', (u'a', 'a-id', 'file', 'a\nb\nc\n'))],
2172
            revision_id='A-id')
2173
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2174
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2175
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
2176
        builder.build_snapshot(['B-id', 'C-id'],
2177
            [('modify', ('a-id', 'a\nb\nc\nd\ne\nf\n'))],
2178
            revision_id='D-id')
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2179
        wt, conflicts = self.do_merge(builder, 'E-id')
2180
        self.assertEqual(0, conflicts)
2181
        # The merge should have simply update the contents of 'a'
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
2182
        self.assertEqual('a\nb\nc\nd\ne\nf\n', wt.get_file_text('a'))
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2183
2184
    def test_conflict_without_lca(self):
2185
        # This test would cause a merge conflict, unless we use the lca trees
2186
        # to determine the real ancestry
2187
        #   A       Path at 'foo'
2188
        #  / \
2189
        # B   C     Path renamed to 'bar' in B
2190
        # |\ /|
2191
        # | X |
2192
        # |/ \|
2193
        # D   E     Path at 'bar' in D and E
2194
        #     |
2195
        #     F     Path at 'baz' in F, which supersedes 'bar' and 'foo'
2196
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2197
        builder.build_snapshot(None,
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2198
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2199
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2200
            revision_id='A-id')
2201
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2202
        builder.build_snapshot(['A-id'],
2203
            [('rename', ('foo', 'bar'))], revision_id='B-id', )
2204
        builder.build_snapshot(['C-id', 'B-id'], # merge the rename
2205
            [('rename', ('foo', 'bar'))], revision_id='E-id')
2206
        builder.build_snapshot(['E-id'],
2207
            [('rename', ('bar', 'baz'))], revision_id='F-id')
2208
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2209
        wt, conflicts = self.do_merge(builder, 'F-id')
2210
        self.assertEqual(0, conflicts)
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2211
        # The merge should simply recognize that the final rename takes
2212
        # precedence
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2213
        self.assertEqual('baz', wt.id2path('foo-id'))
2214
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2215
    def test_other_deletes_lca_renames(self):
2216
        # This test would cause a merge conflict, unless we use the lca trees
2217
        # to determine the real ancestry
2218
        #   A       Path at 'foo'
2219
        #  / \
2220
        # B   C     Path renamed to 'bar' in B
2221
        # |\ /|
2222
        # | X |
2223
        # |/ \|
2224
        # D   E     Path at 'bar' in D and E
2225
        #     |
2226
        #     F     F deletes 'bar'
2227
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2228
        builder.build_snapshot(None,
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2229
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2230
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2231
            revision_id='A-id')
2232
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2233
        builder.build_snapshot(['A-id'],
2234
            [('rename', ('foo', 'bar'))], revision_id='B-id')
2235
        builder.build_snapshot(['C-id', 'B-id'], # merge the rename
2236
            [('rename', ('foo', 'bar'))], revision_id='E-id')
2237
        builder.build_snapshot(['E-id'],
2238
            [('unversion', 'foo-id')], revision_id='F-id')
2239
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2240
        wt, conflicts = self.do_merge(builder, 'F-id')
2241
        self.assertEqual(0, conflicts)
2242
        self.assertRaises(errors.NoSuchId, wt.id2path, 'foo-id')
2243
2244
    def test_executable_changes(self):
2245
        #   A       Path at 'foo'
2246
        #  / \
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2247
        # B   C
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2248
        # |\ /|
2249
        # | X |
2250
        # |/ \|
2251
        # D   E
2252
        #     |
2253
        #     F     Executable bit changed
2254
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2255
        builder.build_snapshot(None,
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2256
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2257
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2258
            revision_id='A-id')
2259
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2260
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2261
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
2262
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2263
        # Have to use a real WT, because BranchBuilder doesn't support exec bit
2264
        wt = self.get_wt_from_builder(builder)
2265
        tt = transform.TreeTransform(wt)
2266
        try:
6885.1.1 by Jelmer Vernooij
Get rid of TreeTransform.trans_id_tree_file_id.
2267
            tt.set_executability(True, tt.trans_id_tree_path('foo'))
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2268
            tt.apply()
2269
        except:
2270
            tt.finalize()
2271
            raise
6809.4.4 by Jelmer Vernooij
Swap arguments for Tree.is_executable.
2272
        self.assertTrue(wt.is_executable('foo'))
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2273
        wt.commit('F-id', rev_id='F-id')
2274
        # Reset to D, so that we can merge F
2275
        wt.set_parent_ids(['D-id'])
2276
        wt.branch.set_last_revision_info(3, 'D-id')
2277
        wt.revert()
6809.4.4 by Jelmer Vernooij
Swap arguments for Tree.is_executable.
2278
        self.assertFalse(wt.is_executable('foo'))
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2279
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2280
        self.assertEqual(0, conflicts)
6809.4.4 by Jelmer Vernooij
Swap arguments for Tree.is_executable.
2281
        self.assertTrue(wt.is_executable('foo'))
3514.4.22 by John Arbash Meinel
Handle executable bit changes as well.
2282
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2283
    def test_create_symlink(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2284
        self.requireFeature(features.SymlinkFeature)
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2285
        #   A
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2286
        #  / \
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2287
        # B   C
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2288
        # |\ /|
2289
        # | X |
2290
        # |/ \|
2291
        # D   E
2292
        #     |
2293
        #     F     Add a symlink 'foo' => 'bar'
2294
        # Have to use a real WT, because BranchBuilder and MemoryTree don't
2295
        # have symlink support
2296
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2297
        builder.build_snapshot(None,
2298
            [('add', (u'', 'a-root-id', 'directory', None))],
2299
            revision_id='A-id')
2300
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2301
        builder.build_snapshot(['A-id'], [], revision_id='B-id')
2302
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
2303
        builder.build_snapshot(['C-id', 'B-id'], [], revision_id='E-id')
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2304
        # Have to use a real WT, because BranchBuilder doesn't support exec bit
2305
        wt = self.get_wt_from_builder(builder)
2306
        os.symlink('bar', 'path/foo')
2307
        wt.add(['foo'], ['foo-id'])
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2308
        self.assertEqual('bar', wt.get_symlink_target('foo'))
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2309
        wt.commit('add symlink', rev_id='F-id')
2310
        # Reset to D, so that we can merge F
2311
        wt.set_parent_ids(['D-id'])
2312
        wt.branch.set_last_revision_info(3, 'D-id')
2313
        wt.revert()
6852.3.1 by Jelmer Vernooij
add Tree.is_versioned.
2314
        self.assertFalse(wt.is_versioned('foo'))
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2315
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2316
        self.assertEqual(0, conflicts)
2317
        self.assertEqual('foo-id', wt.path2id('foo'))
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2318
        self.assertEqual('bar', wt.get_symlink_target('foo'))
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2319
3514.4.30 by John Arbash Meinel
Several updates.
2320
    def test_both_sides_revert(self):
2321
        # Both sides of a criss-cross revert the text to the lca
2322
        #       A    base, introduces 'foo'
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2323
        #       |\
3514.4.30 by John Arbash Meinel
Several updates.
2324
        #       B C  B modifies 'foo', C modifies 'foo'
2325
        #       |X|
2326
        #       D E  D reverts to B, E reverts to C
2327
        # This should conflict
2328
        # This must be done with a real WorkingTree, because normally their
2329
        # inventory contains "None" rather than a real sha1
2330
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2331
        builder.build_snapshot(None,
3514.4.30 by John Arbash Meinel
Several updates.
2332
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2333
             ('add', (u'foo', 'foo-id', 'file', 'A content\n'))],
2334
            revision_id='A-id')
2335
        builder.build_snapshot(['A-id'],
2336
            [('modify', ('foo-id', 'B content\n'))],
2337
            revision_id='B-id')
2338
        builder.build_snapshot(['A-id'],
2339
            [('modify', ('foo-id', 'C content\n'))],
2340
            revision_id='C-id')
2341
        builder.build_snapshot(['C-id', 'B-id'], [],
2342
                revision_id='E-id')
2343
        builder.build_snapshot(['B-id', 'C-id'], [],
2344
                revision_id='D-id')
3514.4.30 by John Arbash Meinel
Several updates.
2345
        wt, conflicts = self.do_merge(builder, 'E-id')
2346
        self.assertEqual(1, conflicts)
2347
        self.assertEqualDiff('<<<<<<< TREE\n'
2348
                             'B content\n'
2349
                             '=======\n'
2350
                             'C content\n'
2351
                             '>>>>>>> MERGE-SOURCE\n',
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
2352
                             wt.get_file_text('foo'))
3514.4.30 by John Arbash Meinel
Several updates.
2353
3514.4.28 by John Arbash Meinel
More symlink tests.
2354
    def test_modified_symlink(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2355
        self.requireFeature(features.SymlinkFeature)
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2356
        #   A       Create symlink foo => bar
2357
        #  / \
2358
        # B   C     B relinks foo => baz
2359
        # |\ /|
2360
        # | X |
2361
        # |/ \|
2362
        # D   E     D & E have foo => baz
2363
        #     |
2364
        #     F     F changes it to bing
2365
        #
2366
        # Merging D & F should result in F cleanly overriding D, because D's
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2367
        # value actually comes from B
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2368
2369
        # Have to use a real WT, because BranchBuilder and MemoryTree don't
2370
        # have symlink support
2371
        wt = self.make_branch_and_tree('path')
2372
        wt.lock_write()
2373
        self.addCleanup(wt.unlock)
2374
        os.symlink('bar', 'path/foo')
2375
        wt.add(['foo'], ['foo-id'])
2376
        wt.commit('add symlink', rev_id='A-id')
2377
        os.remove('path/foo')
2378
        os.symlink('baz', 'path/foo')
2379
        wt.commit('foo => baz', rev_id='B-id')
2380
        wt.set_last_revision('A-id')
2381
        wt.branch.set_last_revision_info(1, 'A-id')
2382
        wt.revert()
2383
        wt.commit('C', rev_id='C-id')
2384
        wt.merge_from_branch(wt.branch, 'B-id')
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2385
        self.assertEqual('baz', wt.get_symlink_target('foo'))
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2386
        wt.commit('E merges C & B', rev_id='E-id')
2387
        os.remove('path/foo')
2388
        os.symlink('bing', 'path/foo')
2389
        wt.commit('F foo => bing', rev_id='F-id')
2390
        wt.set_last_revision('B-id')
2391
        wt.branch.set_last_revision_info(2, 'B-id')
2392
        wt.revert()
2393
        wt.merge_from_branch(wt.branch, 'C-id')
2394
        wt.commit('D merges B & C', rev_id='D-id')
2395
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
3948.1.7 by Vincent Ladeuil
Slight refactoring and test fixing.
2396
        self.assertEqual(0, conflicts)
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2397
        self.assertEqual('bing', wt.get_symlink_target('foo'))
3514.4.27 by John Arbash Meinel
A couple of symlink tests, we need to do more.
2398
3514.4.28 by John Arbash Meinel
More symlink tests.
2399
    def test_renamed_symlink(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2400
        self.requireFeature(features.SymlinkFeature)
3514.4.28 by John Arbash Meinel
More symlink tests.
2401
        #   A       Create symlink foo => bar
2402
        #  / \
2403
        # B   C     B renames foo => barry
2404
        # |\ /|
2405
        # | X |
2406
        # |/ \|
2407
        # D   E     D & E have barry
2408
        #     |
2409
        #     F     F renames barry to blah
2410
        #
2411
        # Merging D & F should result in F cleanly overriding D, because D's
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2412
        # value actually comes from B
3514.4.28 by John Arbash Meinel
More symlink tests.
2413
2414
        wt = self.make_branch_and_tree('path')
2415
        wt.lock_write()
2416
        self.addCleanup(wt.unlock)
2417
        os.symlink('bar', 'path/foo')
2418
        wt.add(['foo'], ['foo-id'])
2419
        wt.commit('A add symlink', rev_id='A-id')
2420
        wt.rename_one('foo', 'barry')
2421
        wt.commit('B foo => barry', rev_id='B-id')
2422
        wt.set_last_revision('A-id')
2423
        wt.branch.set_last_revision_info(1, 'A-id')
2424
        wt.revert()
2425
        wt.commit('C', rev_id='C-id')
2426
        wt.merge_from_branch(wt.branch, 'B-id')
2427
        self.assertEqual('barry', wt.id2path('foo-id'))
6809.4.9 by Jelmer Vernooij
Fix some more tests.
2428
        self.assertEqual('bar', wt.get_symlink_target('barry'))
3514.4.28 by John Arbash Meinel
More symlink tests.
2429
        wt.commit('E merges C & B', rev_id='E-id')
2430
        wt.rename_one('barry', 'blah')
2431
        wt.commit('F barry => blah', rev_id='F-id')
2432
        wt.set_last_revision('B-id')
2433
        wt.branch.set_last_revision_info(2, 'B-id')
2434
        wt.revert()
2435
        wt.merge_from_branch(wt.branch, 'C-id')
2436
        wt.commit('D merges B & C', rev_id='D-id')
2437
        self.assertEqual('barry', wt.id2path('foo-id'))
2438
        # Check the output of the Merger object directly
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2439
        merger = _mod_merge.Merger.from_revision_ids(wt, 'F-id')
3514.4.28 by John Arbash Meinel
More symlink tests.
2440
        merger.merge_type = _mod_merge.Merge3Merger
2441
        merge_obj = merger.make_merger()
2442
        root_id = wt.path2id('')
2443
        entries = list(merge_obj._entries_lca())
2444
        # No content change, just a path change
2445
        self.assertEqual([('foo-id', False,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2446
                           ((u'foo', [u'blah', u'blah']), u'blah', u'barry'),
3514.4.28 by John Arbash Meinel
More symlink tests.
2447
                           ((root_id, [root_id, root_id]), root_id, root_id),
2448
                           ((u'foo', [u'barry', u'foo']), u'blah', u'barry'),
2449
                           ((False, [False, False]), False, False)),
2450
                         ], entries)
2451
        conflicts = wt.merge_from_branch(wt.branch, to_revision='F-id')
2452
        self.assertEqual(0, conflicts)
2453
        self.assertEqual('blah', wt.id2path('foo-id'))
2454
2455
    def test_symlink_no_content_change(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2456
        self.requireFeature(features.SymlinkFeature)
3514.4.28 by John Arbash Meinel
More symlink tests.
2457
        #   A       Create symlink foo => bar
2458
        #  / \
2459
        # B   C     B relinks foo => baz
2460
        # |\ /|
2461
        # | X |
2462
        # |/ \|
2463
        # D   E     D & E have foo => baz
2464
        # |
2465
        # F         F has foo => bing
2466
        #
2467
        # Merging E into F should not cause a conflict, because E doesn't have
2468
        # a content change relative to the LCAs (it does relative to A)
2469
        wt = self.make_branch_and_tree('path')
2470
        wt.lock_write()
2471
        self.addCleanup(wt.unlock)
2472
        os.symlink('bar', 'path/foo')
2473
        wt.add(['foo'], ['foo-id'])
2474
        wt.commit('add symlink', rev_id='A-id')
2475
        os.remove('path/foo')
2476
        os.symlink('baz', 'path/foo')
2477
        wt.commit('foo => baz', rev_id='B-id')
2478
        wt.set_last_revision('A-id')
2479
        wt.branch.set_last_revision_info(1, 'A-id')
2480
        wt.revert()
2481
        wt.commit('C', rev_id='C-id')
2482
        wt.merge_from_branch(wt.branch, 'B-id')
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2483
        self.assertEqual('baz', wt.get_symlink_target('foo'))
3514.4.28 by John Arbash Meinel
More symlink tests.
2484
        wt.commit('E merges C & B', rev_id='E-id')
2485
        wt.set_last_revision('B-id')
2486
        wt.branch.set_last_revision_info(2, 'B-id')
2487
        wt.revert()
2488
        wt.merge_from_branch(wt.branch, 'C-id')
2489
        wt.commit('D merges B & C', rev_id='D-id')
2490
        os.remove('path/foo')
2491
        os.symlink('bing', 'path/foo')
2492
        wt.commit('F foo => bing', rev_id='F-id')
2493
2494
        # Check the output of the Merger object directly
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2495
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.28 by John Arbash Meinel
More symlink tests.
2496
        merger.merge_type = _mod_merge.Merge3Merger
2497
        merge_obj = merger.make_merger()
2498
        # Nothing interesting happened in OTHER relative to BASE
2499
        self.assertEqual([], list(merge_obj._entries_lca()))
2500
        # Now do a real merge, just to test the rest of the stack
2501
        conflicts = wt.merge_from_branch(wt.branch, to_revision='E-id')
2502
        self.assertEqual(0, conflicts)
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2503
        self.assertEqual('bing', wt.get_symlink_target('foo'))
3514.4.28 by John Arbash Meinel
More symlink tests.
2504
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
2505
    def test_symlink_this_changed_kind(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2506
        self.requireFeature(features.SymlinkFeature)
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
2507
        #   A       Nothing
2508
        #  / \
2509
        # B   C     B creates symlink foo => bar
2510
        # |\ /|
2511
        # | X |
2512
        # |/ \|
2513
        # D   E     D changes foo into a file, E has foo => bing
2514
        #
2515
        # Mostly, this is trying to test that we don't try to os.readlink() on
2516
        # a file, or when there is nothing there
2517
        wt = self.make_branch_and_tree('path')
2518
        wt.lock_write()
2519
        self.addCleanup(wt.unlock)
2520
        wt.commit('base', rev_id='A-id')
2521
        os.symlink('bar', 'path/foo')
2522
        wt.add(['foo'], ['foo-id'])
2523
        wt.commit('add symlink foo => bar', rev_id='B-id')
2524
        wt.set_last_revision('A-id')
2525
        wt.branch.set_last_revision_info(1, 'A-id')
2526
        wt.revert()
2527
        wt.commit('C', rev_id='C-id')
2528
        wt.merge_from_branch(wt.branch, 'B-id')
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2529
        self.assertEqual('bar', wt.get_symlink_target('foo'))
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
2530
        os.remove('path/foo')
2531
        # We have to change the link in E, or it won't try to do a comparison
2532
        os.symlink('bing', 'path/foo')
2533
        wt.commit('E merges C & B, overrides to bing', rev_id='E-id')
2534
        wt.set_last_revision('B-id')
2535
        wt.branch.set_last_revision_info(2, 'B-id')
2536
        wt.revert()
2537
        wt.merge_from_branch(wt.branch, 'C-id')
2538
        os.remove('path/foo')
2539
        self.build_tree_contents([('path/foo', 'file content\n')])
2540
        # XXX: workaround, WT doesn't detect kind changes unless you do
2541
        # iter_changes()
2542
        list(wt.iter_changes(wt.basis_tree()))
2543
        wt.commit('D merges B & C, makes it a file', rev_id='D-id')
2544
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2545
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
2546
        merger.merge_type = _mod_merge.Merge3Merger
2547
        merge_obj = merger.make_merger()
2548
        entries = list(merge_obj._entries_lca())
2549
        root_id = wt.path2id('')
2550
        self.assertEqual([('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2551
                           ((None, [u'foo', None]), u'foo', u'foo'),
3514.4.35 by John Arbash Meinel
Add a test that we only call get_symlink_target if the object should be a symlink.
2552
                           ((None, [root_id, None]), root_id, root_id),
2553
                           ((None, [u'foo', None]), u'foo', u'foo'),
2554
                           ((None, [False, None]), False, False)),
2555
                         ], entries)
2556
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2557
    def test_symlink_all_wt(self):
2558
        """Check behavior if all trees are Working Trees."""
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
2559
        self.requireFeature(features.SymlinkFeature)
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2560
        # The big issue is that entry.symlink_target is None for WorkingTrees.
2561
        # So we need to make sure we handle that case correctly.
2562
        #   A   foo => bar
2563
        #   |\
2564
        #   B C B relinks foo => baz
2565
        #   |X|
2566
        #   D E D & E have foo => baz
2567
        #     |
2568
        #     F F changes it to bing
2569
        # Merging D & F should result in F cleanly overriding D, because D's
2570
        # value actually comes from B
2571
2572
        wt = self.make_branch_and_tree('path')
2573
        wt.lock_write()
2574
        self.addCleanup(wt.unlock)
2575
        os.symlink('bar', 'path/foo')
2576
        wt.add(['foo'], ['foo-id'])
2577
        wt.commit('add symlink', rev_id='A-id')
2578
        os.remove('path/foo')
2579
        os.symlink('baz', 'path/foo')
2580
        wt.commit('foo => baz', rev_id='B-id')
2581
        wt.set_last_revision('A-id')
2582
        wt.branch.set_last_revision_info(1, 'A-id')
2583
        wt.revert()
2584
        wt.commit('C', rev_id='C-id')
2585
        wt.merge_from_branch(wt.branch, 'B-id')
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
2586
        self.assertEqual('baz', wt.get_symlink_target('foo'))
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2587
        wt.commit('E merges C & B', rev_id='E-id')
2588
        os.remove('path/foo')
2589
        os.symlink('bing', 'path/foo')
2590
        wt.commit('F foo => bing', rev_id='F-id')
2591
        wt.set_last_revision('B-id')
2592
        wt.branch.set_last_revision_info(2, 'B-id')
2593
        wt.revert()
2594
        wt.merge_from_branch(wt.branch, 'C-id')
2595
        wt.commit('D merges B & C', rev_id='D-id')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2596
        wt_base = wt.controldir.sprout('base', 'A-id').open_workingtree()
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2597
        wt_base.lock_read()
2598
        self.addCleanup(wt_base.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2599
        wt_lca1 = wt.controldir.sprout('b-tree', 'B-id').open_workingtree()
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2600
        wt_lca1.lock_read()
2601
        self.addCleanup(wt_lca1.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2602
        wt_lca2 = wt.controldir.sprout('c-tree', 'C-id').open_workingtree()
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2603
        wt_lca2.lock_read()
2604
        self.addCleanup(wt_lca2.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2605
        wt_other = wt.controldir.sprout('other', 'F-id').open_workingtree()
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2606
        wt_other.lock_read()
2607
        self.addCleanup(wt_other.unlock)
2608
        merge_obj = _mod_merge.Merge3Merger(wt, wt, wt_base,
2609
            wt_other, lca_trees=[wt_lca1, wt_lca2], do_merge=False)
2610
        entries = list(merge_obj._entries_lca())
2611
        root_id = wt.path2id('')
2612
        self.assertEqual([('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2613
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
3514.4.34 by John Arbash Meinel
Handle symlinks properly when objects are not RevisionTrees
2614
                           ((root_id, [root_id, root_id]), root_id, root_id),
2615
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2616
                           ((False, [False, False]), False, False)),
2617
                         ], entries)
2618
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2619
    def test_other_reverted_path_to_base(self):
2620
        #   A       Path at 'foo'
2621
        #  / \
2622
        # B   C     Path at 'bar' in B
2623
        # |\ /|
2624
        # | X |
2625
        # |/ \|
2626
        # D   E     Path at 'bar'
2627
        #     |
2628
        #     F     Path at 'foo'
2629
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2630
        builder.build_snapshot(None,
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2631
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2632
             ('add', (u'foo', 'foo-id', 'file', 'a\nb\nc\n'))],
2633
            revision_id='A-id')
2634
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2635
        builder.build_snapshot(['A-id'],
2636
            [('rename', ('foo', 'bar'))], revision_id='B-id')
2637
        builder.build_snapshot(['C-id', 'B-id'],
2638
            [('rename', ('foo', 'bar'))], revision_id='E-id') # merge the rename
2639
        builder.build_snapshot(['E-id'],
2640
            [('rename', ('bar', 'foo'))], revision_id='F-id') # Rename back to BASE
2641
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2642
        wt, conflicts = self.do_merge(builder, 'F-id')
2643
        self.assertEqual(0, conflicts)
2644
        self.assertEqual('foo', wt.id2path('foo-id'))
2645
2646
    def test_other_reverted_content_to_base(self):
2647
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2648
        builder.build_snapshot(None,
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2649
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2650
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))],
2651
            revision_id='A-id')
2652
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2653
        builder.build_snapshot(['A-id'],
2654
            [('modify', ('foo-id', 'B content\n'))],
2655
            revision_id='B-id')
2656
        builder.build_snapshot(['C-id', 'B-id'],
2657
            [('modify', ('foo-id', 'B content\n'))],
2658
            revision_id='E-id') # merge the content
2659
        builder.build_snapshot(['E-id'],
2660
            [('modify', ('foo-id', 'base content\n'))],
2661
            revision_id='F-id') # Revert back to BASE
2662
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2663
        wt, conflicts = self.do_merge(builder, 'F-id')
2664
        self.assertEqual(0, conflicts)
2665
        # TODO: We need to use the per-file graph to properly select a BASE
3514.4.26 by John Arbash Meinel
Clean up comments, only symlink support left.
2666
        #       before this will work. Or at least use the LCA trees to find
2667
        #       the appropriate content base. (which is B, not A).
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
2668
        self.assertEqual('base content\n', wt.get_file_text('foo'))
3514.4.25 by John Arbash Meinel
A few more merge-level behavior tests.
2669
3514.4.28 by John Arbash Meinel
More symlink tests.
2670
    def test_other_modified_content(self):
2671
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2672
        builder.build_snapshot(None,
3514.4.28 by John Arbash Meinel
More symlink tests.
2673
            [('add', (u'', 'a-root-id', 'directory', None)),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2674
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))],
2675
            revision_id='A-id')
2676
        builder.build_snapshot(['A-id'], [], revision_id='C-id')
2677
        builder.build_snapshot(['A-id'],
2678
            [('modify', ('foo-id', 'B content\n'))],
2679
            revision_id='B-id')
2680
        builder.build_snapshot(['C-id', 'B-id'],
2681
            [('modify', ('foo-id', 'B content\n'))],
2682
            revision_id='E-id') # merge the content
2683
        builder.build_snapshot(['E-id'],
2684
            [('modify', ('foo-id', 'F content\n'))],
2685
            revision_id='F-id') # Override B content
2686
        builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
3514.4.28 by John Arbash Meinel
More symlink tests.
2687
        wt, conflicts = self.do_merge(builder, 'F-id')
2688
        self.assertEqual(0, conflicts)
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
2689
        self.assertEqual('F content\n', wt.get_file_text('foo'))
3514.4.28 by John Arbash Meinel
More symlink tests.
2690
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2691
    def test_all_wt(self):
2692
        """Check behavior if all trees are Working Trees."""
2693
        # The big issue is that entry.revision is None for WorkingTrees. (as is
2694
        # entry.text_sha1, etc. So we need to make sure we handle that case
2695
        # correctly.
2696
        #   A   Content of 'foo', path of 'a'
2697
        #   |\
2698
        #   B C B modifies content, C renames 'a' => 'b'
2699
        #   |X|
2700
        #   D E E updates content, renames 'b' => 'c'
2701
        builder = self.get_builder()
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2702
        builder.build_snapshot(None,
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2703
            [('add', (u'', 'a-root-id', 'directory', None)),
2704
             ('add', (u'a', 'a-id', 'file', 'base content\n')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2705
             ('add', (u'foo', 'foo-id', 'file', 'base content\n'))],
2706
            revision_id='A-id')
2707
        builder.build_snapshot(['A-id'],
2708
            [('modify', ('foo-id', 'B content\n'))],
2709
            revision_id='B-id')
2710
        builder.build_snapshot(['A-id'],
2711
            [('rename', ('a', 'b'))],
2712
            revision_id='C-id')
2713
        builder.build_snapshot(['C-id', 'B-id'],
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2714
            [('rename', ('b', 'c')),
6816.2.3 by Jelmer Vernooij
Port over last uses of build_snapshot.
2715
             ('modify', ('foo-id', 'E content\n'))],
2716
            revision_id='E-id')
2717
        builder.build_snapshot(['B-id', 'C-id'],
2718
            [('rename', ('a', 'b'))], revision_id='D-id') # merged change
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2719
        wt_this = self.get_wt_from_builder(builder)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2720
        wt_base = wt_this.controldir.sprout('base', 'A-id').open_workingtree()
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2721
        wt_base.lock_read()
2722
        self.addCleanup(wt_base.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2723
        wt_lca1 = wt_this.controldir.sprout('b-tree', 'B-id').open_workingtree()
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2724
        wt_lca1.lock_read()
2725
        self.addCleanup(wt_lca1.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2726
        wt_lca2 = wt_this.controldir.sprout('c-tree', 'C-id').open_workingtree()
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2727
        wt_lca2.lock_read()
2728
        self.addCleanup(wt_lca2.unlock)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
2729
        wt_other = wt_this.controldir.sprout('other', 'E-id').open_workingtree()
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2730
        wt_other.lock_read()
2731
        self.addCleanup(wt_other.unlock)
2732
        merge_obj = _mod_merge.Merge3Merger(wt_this, wt_this, wt_base,
2733
            wt_other, lca_trees=[wt_lca1, wt_lca2], do_merge=False)
2734
        entries = list(merge_obj._entries_lca())
2735
        root_id = 'a-root-id'
2736
        self.assertEqual([('a-id', False,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2737
                           ((u'a', [u'c', u'c']), u'c', u'b'),
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2738
                           ((root_id, [root_id, root_id]), root_id, root_id),
2739
                           ((u'a', [u'a', u'b']), u'c', u'b'),
2740
                           ((False, [False, False]), False, False)),
2741
                          ('foo-id', True,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2742
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
3514.4.32 by John Arbash Meinel
Add a test for proper behavior when *everything* is a WT.
2743
                           ((root_id, [root_id, root_id]), root_id, root_id),
2744
                           ((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2745
                           ((False, [False, False]), False, False)),
2746
                         ], entries)
2747
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2748
    def test_nested_tree_unmodified(self):
2749
        # Tested with a real WT, because BranchBuilder/MemoryTree don't handle
2750
        # 'tree-reference'
2751
        wt = self.make_branch_and_tree('tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2752
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2753
        wt.lock_write()
2754
        self.addCleanup(wt.unlock)
2755
        sub_tree = self.make_branch_and_tree('tree/sub-tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2756
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2757
        wt.set_root_id('a-root-id')
2758
        sub_tree.set_root_id('sub-tree-root')
2759
        self.build_tree_contents([('tree/sub-tree/file', 'text1')])
2760
        sub_tree.add('file')
2761
        sub_tree.commit('foo', rev_id='sub-A-id')
2762
        wt.add_reference(sub_tree)
2763
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2764
        # Now create a criss-cross merge in the parent, without modifying the
2765
        # subtree
2766
        wt.commit('B', rev_id='B-id', recursive=None)
2767
        wt.set_last_revision('A-id')
2768
        wt.branch.set_last_revision_info(1, 'A-id')
2769
        wt.commit('C', rev_id='C-id', recursive=None)
2770
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2771
        wt.commit('E', rev_id='E-id', recursive=None)
2772
        wt.set_parent_ids(['B-id', 'C-id'])
2773
        wt.branch.set_last_revision_info(2, 'B-id')
2774
        wt.commit('D', rev_id='D-id', recursive=None)
2775
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2776
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2777
        merger.merge_type = _mod_merge.Merge3Merger
2778
        merge_obj = merger.make_merger()
2779
        entries = list(merge_obj._entries_lca())
2780
        self.assertEqual([], entries)
2781
2782
    def test_nested_tree_subtree_modified(self):
2783
        # Tested with a real WT, because BranchBuilder/MemoryTree don't handle
2784
        # 'tree-reference'
2785
        wt = self.make_branch_and_tree('tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2786
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2787
        wt.lock_write()
2788
        self.addCleanup(wt.unlock)
2789
        sub_tree = self.make_branch_and_tree('tree/sub',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2790
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2791
        wt.set_root_id('a-root-id')
2792
        sub_tree.set_root_id('sub-tree-root')
2793
        self.build_tree_contents([('tree/sub/file', 'text1')])
2794
        sub_tree.add('file')
2795
        sub_tree.commit('foo', rev_id='sub-A-id')
2796
        wt.add_reference(sub_tree)
2797
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2798
        # Now create a criss-cross merge in the parent, without modifying the
2799
        # subtree
2800
        wt.commit('B', rev_id='B-id', recursive=None)
2801
        wt.set_last_revision('A-id')
2802
        wt.branch.set_last_revision_info(1, 'A-id')
2803
        wt.commit('C', rev_id='C-id', recursive=None)
2804
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2805
        self.build_tree_contents([('tree/sub/file', 'text2')])
2806
        sub_tree.commit('modify contents', rev_id='sub-B-id')
2807
        wt.commit('E', rev_id='E-id', recursive=None)
2808
        wt.set_parent_ids(['B-id', 'C-id'])
2809
        wt.branch.set_last_revision_info(2, 'B-id')
2810
        wt.commit('D', rev_id='D-id', recursive=None)
2811
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2812
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2813
        merger.merge_type = _mod_merge.Merge3Merger
2814
        merge_obj = merger.make_merger()
2815
        entries = list(merge_obj._entries_lca())
2816
        # Nothing interesting about this sub-tree, because content changes are
2817
        # computed at a higher level
2818
        self.assertEqual([], entries)
2819
2820
    def test_nested_tree_subtree_renamed(self):
2821
        # Tested with a real WT, because BranchBuilder/MemoryTree don't handle
2822
        # 'tree-reference'
2823
        wt = self.make_branch_and_tree('tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2824
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2825
        wt.lock_write()
2826
        self.addCleanup(wt.unlock)
2827
        sub_tree = self.make_branch_and_tree('tree/sub',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2828
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2829
        wt.set_root_id('a-root-id')
2830
        sub_tree.set_root_id('sub-tree-root')
2831
        self.build_tree_contents([('tree/sub/file', 'text1')])
2832
        sub_tree.add('file')
2833
        sub_tree.commit('foo', rev_id='sub-A-id')
2834
        wt.add_reference(sub_tree)
2835
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2836
        # Now create a criss-cross merge in the parent, without modifying the
2837
        # subtree
2838
        wt.commit('B', rev_id='B-id', recursive=None)
2839
        wt.set_last_revision('A-id')
2840
        wt.branch.set_last_revision_info(1, 'A-id')
2841
        wt.commit('C', rev_id='C-id', recursive=None)
2842
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2843
        wt.rename_one('sub', 'alt_sub')
2844
        wt.commit('E', rev_id='E-id', recursive=None)
2845
        wt.set_last_revision('B-id')
2846
        wt.revert()
2847
        wt.set_parent_ids(['B-id', 'C-id'])
2848
        wt.branch.set_last_revision_info(2, 'B-id')
2849
        wt.commit('D', rev_id='D-id', recursive=None)
2850
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2851
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2852
        merger.merge_type = _mod_merge.Merge3Merger
2853
        merge_obj = merger.make_merger()
2854
        entries = list(merge_obj._entries_lca())
2855
        root_id = 'a-root-id'
2856
        self.assertEqual([('sub-tree-root', False,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2857
                           ((u'sub', [u'alt_sub', u'alt_sub']), u'alt_sub', u'sub'),
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2858
                           ((root_id, [root_id, root_id]), root_id, root_id),
2859
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2860
                           ((False, [False, False]), False, False)),
2861
                         ], entries)
2862
2863
    def test_nested_tree_subtree_renamed_and_modified(self):
2864
        # Tested with a real WT, because BranchBuilder/MemoryTree don't handle
2865
        # 'tree-reference'
2866
        wt = self.make_branch_and_tree('tree',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2867
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2868
        wt.lock_write()
2869
        self.addCleanup(wt.unlock)
2870
        sub_tree = self.make_branch_and_tree('tree/sub',
6437.14.2 by Jelmer Vernooij
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.
2871
            format='development-subtree')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2872
        wt.set_root_id('a-root-id')
2873
        sub_tree.set_root_id('sub-tree-root')
2874
        self.build_tree_contents([('tree/sub/file', 'text1')])
2875
        sub_tree.add('file')
2876
        sub_tree.commit('foo', rev_id='sub-A-id')
2877
        wt.add_reference(sub_tree)
2878
        wt.commit('set text to 1', rev_id='A-id', recursive=None)
2879
        # Now create a criss-cross merge in the parent, without modifying the
2880
        # subtree
2881
        wt.commit('B', rev_id='B-id', recursive=None)
2882
        wt.set_last_revision('A-id')
2883
        wt.branch.set_last_revision_info(1, 'A-id')
2884
        wt.commit('C', rev_id='C-id', recursive=None)
2885
        wt.merge_from_branch(wt.branch, to_revision='B-id')
2886
        self.build_tree_contents([('tree/sub/file', 'text2')])
2887
        sub_tree.commit('modify contents', rev_id='sub-B-id')
2888
        wt.rename_one('sub', 'alt_sub')
2889
        wt.commit('E', rev_id='E-id', recursive=None)
2890
        wt.set_last_revision('B-id')
2891
        wt.revert()
2892
        wt.set_parent_ids(['B-id', 'C-id'])
2893
        wt.branch.set_last_revision_info(2, 'B-id')
2894
        wt.commit('D', rev_id='D-id', recursive=None)
2895
6719.1.4 by Jelmer Vernooij
Fix remaining tests.
2896
        merger = _mod_merge.Merger.from_revision_ids(wt, 'E-id')
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2897
        merger.merge_type = _mod_merge.Merge3Merger
2898
        merge_obj = merger.make_merger()
2899
        entries = list(merge_obj._entries_lca())
2900
        root_id = 'a-root-id'
2901
        self.assertEqual([('sub-tree-root', False,
6883.10.1 by Jelmer Vernooij
Fix more tets.
2902
                           ((u'sub', [u'alt_sub', u'alt_sub']), u'alt_sub', u'sub'),
3514.4.33 by John Arbash Meinel
Implement support for 'tree-reference'.
2903
                           ((root_id, [root_id, root_id]), root_id, root_id),
2904
                           ((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2905
                           ((False, [False, False]), False, False)),
2906
                         ], entries)
2907
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2908
2909
class TestLCAMultiWay(tests.TestCase):
2910
3514.4.30 by John Arbash Meinel
Several updates.
2911
    def assertLCAMultiWay(self, expected, base, lcas, other, this,
2912
                          allow_overriding_lca=True):
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2913
        self.assertEqual(expected, _mod_merge.Merge3Merger._lca_multi_way(
3514.4.30 by John Arbash Meinel
Several updates.
2914
                                (base, lcas), other, this,
2915
                                allow_overriding_lca=allow_overriding_lca))
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2916
2917
    def test_other_equal_equal_lcas(self):
2918
        """Test when OTHER=LCA and all LCAs are identical."""
2919
        self.assertLCAMultiWay('this',
2920
            'bval', ['bval', 'bval'], 'bval', 'bval')
2921
        self.assertLCAMultiWay('this',
2922
            'bval', ['lcaval', 'lcaval'], 'lcaval', 'bval')
2923
        self.assertLCAMultiWay('this',
2924
            'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'bval')
2925
        self.assertLCAMultiWay('this',
2926
            'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', 'tval')
2927
        self.assertLCAMultiWay('this',
2928
            'bval', ['lcaval', 'lcaval', 'lcaval'], 'lcaval', None)
2929
2930
    def test_other_equal_this(self):
2931
        """Test when other and this are identical."""
2932
        self.assertLCAMultiWay('this',
2933
            'bval', ['bval', 'bval'], 'oval', 'oval')
2934
        self.assertLCAMultiWay('this',
2935
            'bval', ['lcaval', 'lcaval'], 'oval', 'oval')
2936
        self.assertLCAMultiWay('this',
2937
            'bval', ['cval', 'dval'], 'oval', 'oval')
2938
        self.assertLCAMultiWay('this',
2939
            'bval', [None, 'lcaval'], 'oval', 'oval')
2940
        self.assertLCAMultiWay('this',
2941
            None, [None, 'lcaval'], 'oval', 'oval')
2942
        self.assertLCAMultiWay('this',
2943
            None, ['lcaval', 'lcaval'], 'oval', 'oval')
2944
        self.assertLCAMultiWay('this',
2945
            None, ['cval', 'dval'], 'oval', 'oval')
2946
        self.assertLCAMultiWay('this',
2947
            None, ['cval', 'dval'], None, None)
2948
        self.assertLCAMultiWay('this',
2949
            None, ['cval', 'dval', 'eval', 'fval'], 'oval', 'oval')
2950
2951
    def test_no_lcas(self):
2952
        self.assertLCAMultiWay('this',
2953
            'bval', [], 'bval', 'tval')
2954
        self.assertLCAMultiWay('other',
2955
            'bval', [], 'oval', 'bval')
2956
        self.assertLCAMultiWay('conflict',
2957
            'bval', [], 'oval', 'tval')
2958
        self.assertLCAMultiWay('this',
2959
            'bval', [], 'oval', 'oval')
2960
2961
    def test_lca_supersedes_other_lca(self):
2962
        """If one lca == base, the other lca takes precedence"""
2963
        self.assertLCAMultiWay('this',
2964
            'bval', ['bval', 'lcaval'], 'lcaval', 'tval')
2965
        self.assertLCAMultiWay('this',
2966
            'bval', ['bval', 'lcaval'], 'lcaval', 'bval')
2967
        # This is actually considered a 'revert' because the 'lcaval' in LCAS
2968
        # supersedes the BASE val (in the other LCA) but then OTHER reverts it
2969
        # back to bval.
2970
        self.assertLCAMultiWay('other',
2971
            'bval', ['bval', 'lcaval'], 'bval', 'lcaval')
2972
        self.assertLCAMultiWay('conflict',
2973
            'bval', ['bval', 'lcaval'], 'bval', 'tval')
2974
2975
    def test_other_and_this_pick_different_lca(self):
2976
        # OTHER and THIS resolve the lca conflict in different ways
2977
        self.assertLCAMultiWay('conflict',
2978
            'bval', ['lca1val', 'lca2val'], 'lca1val', 'lca2val')
2979
        self.assertLCAMultiWay('conflict',
2980
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'lca2val')
2981
        self.assertLCAMultiWay('conflict',
2982
            'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'lca2val')
2983
2984
    def test_other_in_lca(self):
2985
        # OTHER takes a value of one of the LCAs, THIS takes a new value, which
2986
        # theoretically supersedes both LCA values and 'wins'
2987
        self.assertLCAMultiWay('this',
2988
            'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval')
2989
        self.assertLCAMultiWay('this',
2990
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval')
3514.4.30 by John Arbash Meinel
Several updates.
2991
        self.assertLCAMultiWay('conflict',
2992
            'bval', ['lca1val', 'lca2val'], 'lca1val', 'newval',
2993
            allow_overriding_lca=False)
2994
        self.assertLCAMultiWay('conflict',
2995
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'newval',
2996
            allow_overriding_lca=False)
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
2997
        # THIS reverted back to BASE, but that is an explicit supersede of all
2998
        # LCAs
2999
        self.assertLCAMultiWay('this',
3000
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval')
3001
        self.assertLCAMultiWay('this',
3002
            'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval')
3514.4.30 by John Arbash Meinel
Several updates.
3003
        self.assertLCAMultiWay('conflict',
3004
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'lca1val', 'bval',
3005
            allow_overriding_lca=False)
3006
        self.assertLCAMultiWay('conflict',
3007
            'bval', ['lca1val', 'lca2val', 'bval'], 'lca1val', 'bval',
3008
            allow_overriding_lca=False)
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
3009
3010
    def test_this_in_lca(self):
3011
        # THIS takes a value of one of the LCAs, OTHER takes a new value, which
3012
        # theoretically supersedes both LCA values and 'wins'
3013
        self.assertLCAMultiWay('other',
3014
            'bval', ['lca1val', 'lca2val'], 'oval', 'lca1val')
3015
        self.assertLCAMultiWay('other',
3016
            'bval', ['lca1val', 'lca2val'], 'oval', 'lca2val')
3514.4.30 by John Arbash Meinel
Several updates.
3017
        self.assertLCAMultiWay('conflict',
3018
            'bval', ['lca1val', 'lca2val'], 'oval', 'lca1val',
3019
            allow_overriding_lca=False)
3020
        self.assertLCAMultiWay('conflict',
3021
            'bval', ['lca1val', 'lca2val'], 'oval', 'lca2val',
3022
            allow_overriding_lca=False)
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
3023
        # OTHER reverted back to BASE, but that is an explicit supersede of all
3024
        # LCAs
3025
        self.assertLCAMultiWay('other',
3026
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'bval', 'lca3val')
3514.4.30 by John Arbash Meinel
Several updates.
3027
        self.assertLCAMultiWay('conflict',
3028
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'bval', 'lca3val',
3029
            allow_overriding_lca=False)
3514.4.21 by John Arbash Meinel
Hook up the lca-way logic into the path handlers.
3030
3031
    def test_all_differ(self):
3032
        self.assertLCAMultiWay('conflict',
3033
            'bval', ['lca1val', 'lca2val'], 'oval', 'tval')
3034
        self.assertLCAMultiWay('conflict',
3035
            'bval', ['lca1val', 'lca2val', 'lca2val'], 'oval', 'tval')
3036
        self.assertLCAMultiWay('conflict',
3037
            'bval', ['lca1val', 'lca2val', 'lca3val'], 'oval', 'tval')
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3038
3039
3040
class TestConfigurableFileMerger(tests.TestCaseWithTransport):
3041
4797.9.2 by Vincent Ladeuil
More tests.
3042
    def setUp(self):
3043
        super(TestConfigurableFileMerger, self).setUp()
3044
        self.calls = []
3045
3046
    def get_merger_factory(self):
3047
        # Allows  the inner methods to access the test attributes
5340.15.1 by John Arbash Meinel
supersede exc-info branch
3048
        calls = self.calls
4797.9.2 by Vincent Ladeuil
More tests.
3049
3050
        class FooMerger(_mod_merge.ConfigurableFileMerger):
4797.5.3 by Robert Collins
Tweak ConfigurableFileMerger to use class variables rather than requiring __init__ wrapping as future proofing for helper functions.
3051
            name_prefix = "foo"
4797.9.1 by Vincent Ladeuil
No test was exercising the faulty code path.
3052
            default_files = ['bar']
4797.9.2 by Vincent Ladeuil
More tests.
3053
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3054
            def merge_text(self, params):
5340.15.1 by John Arbash Meinel
supersede exc-info branch
3055
                calls.append('merge_text')
4797.9.1 by Vincent Ladeuil
No test was exercising the faulty code path.
3056
                return ('not_applicable', None)
4797.9.2 by Vincent Ladeuil
More tests.
3057
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3058
        def factory(merger):
4797.9.2 by Vincent Ladeuil
More tests.
3059
            result = FooMerger(merger)
3060
            # Make sure we start with a clean slate
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3061
            self.assertEqual(None, result.affected_files)
4797.9.2 by Vincent Ladeuil
More tests.
3062
            # Track the original merger
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3063
            self.merger = result
3064
            return result
4797.9.2 by Vincent Ladeuil
More tests.
3065
3066
        return factory
3067
3068
    def _install_hook(self, factory):
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3069
        _mod_merge.Merger.hooks.install_named_hook('merge_file_content',
4797.9.1 by Vincent Ladeuil
No test was exercising the faulty code path.
3070
                                                   factory, 'test factory')
4797.9.2 by Vincent Ladeuil
More tests.
3071
3072
    def make_builder(self):
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3073
        builder = test_merge_core.MergeBuilder(self.test_base_dir)
3074
        self.addCleanup(builder.cleanup)
4797.9.2 by Vincent Ladeuil
More tests.
3075
        return builder
3076
3077
    def make_text_conflict(self, file_name='bar'):
3078
        factory = self.get_merger_factory()
3079
        self._install_hook(factory)
3080
        builder = self.make_builder()
3081
        builder.add_file('bar-id', builder.tree_root, file_name, 'text1', True)
4797.9.1 by Vincent Ladeuil
No test was exercising the faulty code path.
3082
        builder.change_contents('bar-id', other='text4', this='text3')
4797.9.2 by Vincent Ladeuil
More tests.
3083
        return builder
3084
3085
    def make_kind_change(self):
3086
        factory = self.get_merger_factory()
3087
        self._install_hook(factory)
3088
        builder = self.make_builder()
3089
        builder.add_file('bar-id', builder.tree_root, 'bar', 'text1', True,
3090
                         this=False)
3091
        builder.add_dir('bar-dir', builder.tree_root, 'bar-id',
3092
                        base=False, other=False)
3093
        return builder
3094
4797.21.1 by Aaron Bentley
Fix merge when this_tree is not a WorkingTree.
3095
    def test_uses_this_branch(self):
3096
        builder = self.make_text_conflict()
3097
        tt = builder.make_preview_transform()
3098
        self.addCleanup(tt.finalize)
3099
4797.9.2 by Vincent Ladeuil
More tests.
3100
    def test_affected_files_cached(self):
3101
        """Ensures that the config variable is cached"""
3102
        builder = self.make_text_conflict()
4797.5.2 by Robert Collins
Refactor NewsMerger into a reusable base class merge.ConfigurableFileMerger.
3103
        conflicts = builder.merge()
3104
        # The hook should set the variable
4797.9.1 by Vincent Ladeuil
No test was exercising the faulty code path.
3105
        self.assertEqual(['bar'], self.merger.affected_files)
4797.9.2 by Vincent Ladeuil
More tests.
3106
        self.assertEqual(1, len(conflicts))
3107
3108
    def test_hook_called_for_text_conflicts(self):
3109
        builder = self.make_text_conflict()
3110
        conflicts = builder.merge()
3111
        # The hook should call the merge_text() method
3112
        self.assertEqual(['merge_text'], self.calls)
3113
3114
    def test_hook_not_called_for_kind_change(self):
3115
        builder = self.make_kind_change()
3116
        conflicts = builder.merge()
3117
        # The hook should not call the merge_text() method
3118
        self.assertEqual([], self.calls)
3119
3120
    def test_hook_not_called_for_other_files(self):
3121
        builder = self.make_text_conflict('foobar')
3122
        conflicts = builder.merge()
3123
        # The hook should not call the merge_text() method
3124
        self.assertEqual([], self.calls)
5246.2.34 by Andrew Bennetts
Delete test_merge_into, and put those tests directly in test_merge.
3125
3126
3127
class TestMergeIntoBase(tests.TestCaseWithTransport):
3128
3129
    def setup_simple_branch(self, relpath, shape=None, root_id=None):
3130
        """One commit, containing tree specified by optional shape.
3131
        
3132
        Default is empty tree (just root entry).
3133
        """
3134
        if root_id is None:
3135
            root_id = '%s-root-id' % (relpath,)
3136
        wt = self.make_branch_and_tree(relpath)
3137
        wt.set_root_id(root_id)
3138
        if shape is not None:
3139
            adjusted_shape = [relpath + '/' + elem for elem in shape]
3140
            self.build_tree(adjusted_shape)
3141
            ids = ['%s-%s-id' % (relpath, basename(elem.rstrip('/')))
3142
                   for elem in shape]
3143
            wt.add(shape, ids=ids)
3144
        rev_id = 'r1-%s' % (relpath,)
3145
        wt.commit("Initial commit of %s" % (relpath,), rev_id=rev_id)
3146
        self.assertEqual(root_id, wt.path2id(''))
3147
        return wt
3148
3149
    def setup_two_branches(self, custom_root_ids=True):
3150
        """Setup 2 branches, one will be a library, the other a project."""
3151
        if custom_root_ids:
3152
            root_id = None
3153
        else:
3154
            root_id = inventory.ROOT_ID
3155
        project_wt = self.setup_simple_branch(
3156
            'project', ['README', 'dir/', 'dir/file.c'],
3157
            root_id)
3158
        lib_wt = self.setup_simple_branch(
3159
            'lib1', ['README', 'Makefile', 'foo.c'], root_id)
3160
3161
        return project_wt, lib_wt
3162
3163
    def do_merge_into(self, location, merge_as):
3164
        """Helper for using MergeIntoMerger.
3165
        
3166
        :param location: location of directory to merge from, either the
3167
            location of a branch or of a path inside a branch.
3168
        :param merge_as: the path in a tree to add the new directory as.
3169
        :returns: the conflicts from 'do_merge'.
3170
        """
3171
        operation = cleanup.OperationWithCleanups(self._merge_into)
3172
        return operation.run(location, merge_as)
3173
3174
    def _merge_into(self, op, location, merge_as):
3175
        # Open and lock the various tree and branch objects
3176
        wt, subdir_relpath = WorkingTree.open_containing(merge_as)
3177
        op.add_cleanup(wt.lock_write().unlock)
3178
        branch_to_merge, subdir_to_merge = _mod_branch.Branch.open_containing(
3179
            location)
3180
        op.add_cleanup(branch_to_merge.lock_read().unlock)
3181
        other_tree = branch_to_merge.basis_tree()
3182
        op.add_cleanup(other_tree.lock_read().unlock)
3183
        # Perform the merge
3184
        merger = _mod_merge.MergeIntoMerger(this_tree=wt, other_tree=other_tree,
3185
            other_branch=branch_to_merge, target_subdir=subdir_relpath,
3186
            source_subpath=subdir_to_merge)
3187
        merger.set_base_revision(_mod_revision.NULL_REVISION, branch_to_merge)
3188
        conflicts = merger.do_merge()
3189
        merger.set_pending()
3190
        return conflicts
3191
3192
    def assertTreeEntriesEqual(self, expected_entries, tree):
3193
        """Assert that 'tree' contains the expected inventory entries.
3194
3195
        :param expected_entries: sequence of (path, file-id) pairs.
3196
        """
3197
        files = [(path, ie.file_id) for path, ie in tree.iter_entries_by_dir()]
3198
        self.assertEqual(expected_entries, files)
3199
3200
3201
class TestMergeInto(TestMergeIntoBase):
3202
3203
    def test_newdir_with_unique_roots(self):
3204
        """Merge a branch with a unique root into a new directory."""
3205
        project_wt, lib_wt = self.setup_two_branches()
3206
        self.do_merge_into('lib1', 'project/lib1')
3207
        project_wt.lock_read()
3208
        self.addCleanup(project_wt.unlock)
3209
        # The r1-lib1 revision should be merged into this one
3210
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
3211
        self.assertTreeEntriesEqual(
3212
            [('', 'project-root-id'),
3213
             ('README', 'project-README-id'),
3214
             ('dir', 'project-dir-id'),
3215
             ('lib1', 'lib1-root-id'),
3216
             ('dir/file.c', 'project-file.c-id'),
3217
             ('lib1/Makefile', 'lib1-Makefile-id'),
3218
             ('lib1/README', 'lib1-README-id'),
3219
             ('lib1/foo.c', 'lib1-foo.c-id'),
3220
            ], project_wt)
3221
3222
    def test_subdir(self):
3223
        """Merge a branch into a subdirectory of an existing directory."""
3224
        project_wt, lib_wt = self.setup_two_branches()
3225
        self.do_merge_into('lib1', 'project/dir/lib1')
3226
        project_wt.lock_read()
3227
        self.addCleanup(project_wt.unlock)
3228
        # The r1-lib1 revision should be merged into this one
3229
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
3230
        self.assertTreeEntriesEqual(
3231
            [('', 'project-root-id'),
3232
             ('README', 'project-README-id'),
3233
             ('dir', 'project-dir-id'),
3234
             ('dir/file.c', 'project-file.c-id'),
3235
             ('dir/lib1', 'lib1-root-id'),
3236
             ('dir/lib1/Makefile', 'lib1-Makefile-id'),
3237
             ('dir/lib1/README', 'lib1-README-id'),
3238
             ('dir/lib1/foo.c', 'lib1-foo.c-id'),
3239
            ], project_wt)
3240
3241
    def test_newdir_with_repeat_roots(self):
3242
        """If the file-id of the dir to be merged already exists a new ID will
3243
        be allocated to let the merge happen.
3244
        """
3245
        project_wt, lib_wt = self.setup_two_branches(custom_root_ids=False)
3246
        root_id = project_wt.path2id('')
3247
        self.do_merge_into('lib1', 'project/lib1')
3248
        project_wt.lock_read()
3249
        self.addCleanup(project_wt.unlock)
3250
        # The r1-lib1 revision should be merged into this one
3251
        self.assertEqual(['r1-project', 'r1-lib1'], project_wt.get_parent_ids())
3252
        new_lib1_id = project_wt.path2id('lib1')
3253
        self.assertNotEqual(None, new_lib1_id)
3254
        self.assertTreeEntriesEqual(
3255
            [('', root_id),
3256
             ('README', 'project-README-id'),
3257
             ('dir', 'project-dir-id'),
3258
             ('lib1', new_lib1_id),
3259
             ('dir/file.c', 'project-file.c-id'),
3260
             ('lib1/Makefile', 'lib1-Makefile-id'),
3261
             ('lib1/README', 'lib1-README-id'),
3262
             ('lib1/foo.c', 'lib1-foo.c-id'),
3263
            ], project_wt)
3264
3265
    def test_name_conflict(self):
3266
        """When the target directory name already exists a conflict is
3267
        generated and the original directory is renamed to foo.moved.
3268
        """
3269
        dest_wt = self.setup_simple_branch('dest', ['dir/', 'dir/file.txt'])
3270
        src_wt = self.setup_simple_branch('src', ['README'])
3271
        conflicts = self.do_merge_into('src', 'dest/dir')
3272
        self.assertEqual(1, conflicts)
3273
        dest_wt.lock_read()
3274
        self.addCleanup(dest_wt.unlock)
3275
        # The r1-lib1 revision should be merged into this one
3276
        self.assertEqual(['r1-dest', 'r1-src'], dest_wt.get_parent_ids())
3277
        self.assertTreeEntriesEqual(
3278
            [('', 'dest-root-id'),
3279
             ('dir', 'src-root-id'),
3280
             ('dir.moved', 'dest-dir-id'),
3281
             ('dir/README', 'src-README-id'),
3282
             ('dir.moved/file.txt', 'dest-file.txt-id'),
3283
            ], dest_wt)
3284
3285
    def test_file_id_conflict(self):
3286
        """A conflict is generated if the merge-into adds a file (or other
3287
        inventory entry) with a file-id that already exists in the target tree.
3288
        """
3289
        dest_wt = self.setup_simple_branch('dest', ['file.txt'])
3290
        # Make a second tree with a file-id that will clash with file.txt in
3291
        # dest.
3292
        src_wt = self.make_branch_and_tree('src')
3293
        self.build_tree(['src/README'])
3294
        src_wt.add(['README'], ids=['dest-file.txt-id'])
3295
        src_wt.commit("Rev 1 of src.", rev_id='r1-src')
3296
        conflicts = self.do_merge_into('src', 'dest/dir')
3297
        # This is an edge case that shouldn't happen to users very often.  So
3298
        # we don't care really about the exact presentation of the conflict,
3299
        # just that there is one.
3300
        self.assertEqual(1, conflicts)
3301
3302
    def test_only_subdir(self):
3303
        """When the location points to just part of a tree, merge just that
3304
        subtree.
3305
        """
3306
        dest_wt = self.setup_simple_branch('dest')
3307
        src_wt = self.setup_simple_branch(
3308
            'src', ['hello.txt', 'dir/', 'dir/foo.c'])
3309
        conflicts = self.do_merge_into('src/dir', 'dest/dir')
3310
        dest_wt.lock_read()
3311
        self.addCleanup(dest_wt.unlock)
3312
        # The r1-lib1 revision should NOT be merged into this one (this is a
3313
        # partial merge).
3314
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3315
        self.assertTreeEntriesEqual(
3316
            [('', 'dest-root-id'),
3317
             ('dir', 'src-dir-id'),
3318
             ('dir/foo.c', 'src-foo.c-id'),
3319
            ], dest_wt)
3320
3321
    def test_only_file(self):
3322
        """An edge case: merge just one file, not a whole dir."""
3323
        dest_wt = self.setup_simple_branch('dest')
3324
        two_file_wt = self.setup_simple_branch(
3325
            'two-file', ['file1.txt', 'file2.txt'])
3326
        conflicts = self.do_merge_into('two-file/file1.txt', 'dest/file1.txt')
3327
        dest_wt.lock_read()
3328
        self.addCleanup(dest_wt.unlock)
3329
        # The r1-lib1 revision should NOT be merged into this one
3330
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3331
        self.assertTreeEntriesEqual(
3332
            [('', 'dest-root-id'), ('file1.txt', 'two-file-file1.txt-id')],
3333
            dest_wt)
3334
3335
    def test_no_such_source_path(self):
3336
        """PathNotInTree is raised if the specified path in the source tree
3337
        does not exist.
3338
        """
3339
        dest_wt = self.setup_simple_branch('dest')
3340
        two_file_wt = self.setup_simple_branch('src', ['dir/'])
3341
        self.assertRaises(_mod_merge.PathNotInTree, self.do_merge_into,
3342
            'src/no-such-dir', 'dest/foo')
3343
        dest_wt.lock_read()
3344
        self.addCleanup(dest_wt.unlock)
3345
        # The dest tree is unmodified.
3346
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3347
        self.assertTreeEntriesEqual([('', 'dest-root-id')], dest_wt)
3348
3349
    def test_no_such_target_path(self):
3350
        """PathNotInTree is also raised if the specified path in the target
3351
        tree does not exist.
3352
        """
3353
        dest_wt = self.setup_simple_branch('dest')
3354
        two_file_wt = self.setup_simple_branch('src', ['file.txt'])
3355
        self.assertRaises(_mod_merge.PathNotInTree, self.do_merge_into,
3356
            'src', 'dest/no-such-dir/foo')
3357
        dest_wt.lock_read()
3358
        self.addCleanup(dest_wt.unlock)
3359
        # The dest tree is unmodified.
3360
        self.assertEqual(['r1-dest'], dest_wt.get_parent_ids())
3361
        self.assertTreeEntriesEqual([('', 'dest-root-id')], dest_wt)
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3362
3363
3364
class TestMergeHooks(TestCaseWithTransport):
3365
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3366
    def setUp(self):
3367
        super(TestMergeHooks, self).setUp()
3368
        self.tree_a = self.make_branch_and_tree('tree_a')
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3369
        self.build_tree_contents([('tree_a/file', 'content_1')])
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3370
        self.tree_a.add('file', 'file-id')
3371
        self.tree_a.commit('added file')
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3372
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
3373
        self.tree_b = self.tree_a.controldir.sprout('tree_b').open_workingtree()
6388.1.4 by Jelmer Vernooij
Fix tests.
3374
        self.build_tree_contents([('tree_b/file', 'content_2')])
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3375
        self.tree_b.commit('modify file')
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3376
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3377
    def test_pre_merge_hook_inject_different_tree(self):
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
3378
        tree_c = self.tree_b.controldir.sprout('tree_c').open_workingtree()
6388.1.4 by Jelmer Vernooij
Fix tests.
3379
        self.build_tree_contents([('tree_c/file', 'content_3')])
3380
        tree_c.commit("more content")
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3381
        calls = []
6388.1.4 by Jelmer Vernooij
Fix tests.
3382
        def factory(merger):
3383
            self.assertIsInstance(merger, _mod_merge.Merge3Merger)
3384
            merger.other_tree = tree_c
3385
            calls.append(merger)
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3386
        _mod_merge.Merger.hooks.install_named_hook('pre_merge',
3387
                                                   factory, 'test factory')
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3388
        self.tree_a.merge_from_branch(self.tree_b.branch)
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3389
6388.1.4 by Jelmer Vernooij
Fix tests.
3390
        self.assertFileEqual("content_3", 'tree_a/file')
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3391
        self.assertLength(1, calls)
3392
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3393
    def test_post_merge_hook_called(self):
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3394
        calls = []
6388.1.4 by Jelmer Vernooij
Fix tests.
3395
        def factory(merger):
3396
            self.assertIsInstance(merger, _mod_merge.Merge3Merger)
3397
            calls.append(merger)
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3398
        _mod_merge.Merger.hooks.install_named_hook('post_merge',
3399
                                                   factory, 'test factory')
3400
6388.1.7 by Jelmer Vernooij
Review feedback from Vila.
3401
        self.tree_a.merge_from_branch(self.tree_b.branch)
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3402
6388.1.4 by Jelmer Vernooij
Fix tests.
3403
        self.assertFileEqual("content_2", 'tree_a/file')
6388.1.3 by Jelmer Vernooij
Add pre and post merge hooks.
3404
        self.assertLength(1, calls)