1
# Copyright (C) 2006 Canonical Ltd
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.
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.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# Author: Aaron Bentley <aaron.bentley@utoronto.ca>
19
"""Black-box tests for bzr merge.
24
from bzrlib.branch import Branch
25
from bzrlib.bzrdir import BzrDir
26
from bzrlib.osutils import abspath
27
from bzrlib.tests.blackbox import ExternalBase
28
import bzrlib.urlutils as urlutils
29
from bzrlib.workingtree import WorkingTree
32
class TestMerge(ExternalBase):
34
def example_branch(test):
36
file('hello', 'wt').write('foo')
37
test.runbzr('add hello')
38
test.runbzr('commit -m setup hello')
39
file('goodbye', 'wt').write('baz')
40
test.runbzr('add goodbye')
41
test.runbzr('commit -m setup goodbye')
43
def test_merge_reprocess(self):
44
d = BzrDir.create_standalone_workingtree('.')
46
self.run_bzr('merge', '.', '--reprocess', '--merge-type', 'weave')
49
from bzrlib.branch import Branch
55
self.runbzr('branch a b')
57
file('goodbye', 'wt').write('quux')
58
self.runbzr(['commit', '-m', "more u's are always good"])
61
file('hello', 'wt').write('quuux')
62
# We can't merge when there are in-tree changes
63
self.runbzr('merge ../b', retcode=3)
64
self.runbzr(['commit', '-m', "Like an epidemic of u's"])
65
self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
67
self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
68
self.runbzr('revert --no-backup')
69
self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
70
self.runbzr('revert --no-backup')
71
self.runbzr('merge ../b -r last:1..last:1 --reprocess')
72
self.runbzr('revert --no-backup')
73
self.runbzr('merge ../b -r last:1')
74
self.check_file_contents('goodbye', 'quux')
75
# Merging a branch pulls its revision into the tree
76
a = WorkingTree.open('.')
77
b = Branch.open('../b')
78
a.branch.repository.get_revision_xml(b.last_revision())
79
self.log('pending merges: %s', a.pending_merges())
80
self.assertEquals(a.pending_merges(),
82
self.runbzr('commit -m merged')
83
self.runbzr('merge ../b -r last:1')
84
self.assertEqual(a.pending_merges(), [])
86
def test_merge_with_missing_file(self):
87
"""Merge handles missing file conflicts"""
91
print >> file('sub/a.txt', 'wb'), "hello"
92
print >> file('b.txt', 'wb'), "hello"
93
print >> file('sub/c.txt', 'wb'), "hello"
96
self.runbzr(('commit', '-m', 'added a'))
97
self.runbzr('branch . ../b')
98
print >> file('sub/a.txt', 'ab'), "there"
99
print >> file('b.txt', 'ab'), "there"
100
print >> file('sub/c.txt', 'ab'), "there"
101
self.runbzr(('commit', '-m', 'Added there'))
102
os.unlink('sub/a.txt')
103
os.unlink('sub/c.txt')
106
self.runbzr(('commit', '-m', 'Removed a.txt'))
108
print >> file('sub/a.txt', 'ab'), "something"
109
print >> file('b.txt', 'ab'), "something"
110
print >> file('sub/c.txt', 'ab'), "something"
111
self.runbzr(('commit', '-m', 'Modified a.txt'))
112
self.runbzr('merge ../a/', retcode=1)
113
self.assert_(os.path.exists('sub/a.txt.THIS'))
114
self.assert_(os.path.exists('sub/a.txt.BASE'))
116
self.runbzr('merge ../b/', retcode=1)
117
self.assert_(os.path.exists('sub/a.txt.OTHER'))
118
self.assert_(os.path.exists('sub/a.txt.BASE'))
120
def test_merge_remember(self):
121
"""Merge changes from one branch to another and test parent location."""
122
tree_a = self.make_branch_and_tree('branch_a')
123
branch_a = tree_a.branch
124
self.build_tree(['branch_a/a'])
126
tree_a.commit('commit a')
127
branch_b = branch_a.bzrdir.sprout('branch_b').open_branch()
128
tree_b = branch_b.bzrdir.open_workingtree()
129
branch_c = branch_a.bzrdir.sprout('branch_c').open_branch()
130
tree_c = branch_c.bzrdir.open_workingtree()
131
self.build_tree(['branch_a/b'])
133
tree_a.commit('commit b')
134
self.build_tree(['branch_c/c'])
136
tree_c.commit('commit c')
138
parent = branch_b.get_parent()
139
branch_b.set_parent(None)
140
self.assertEqual(None, branch_b.get_parent())
141
# test merge for failure without parent set
143
out = self.runbzr('merge', retcode=3)
144
self.assertEquals(out,
145
('','bzr: ERROR: No location specified or remembered\n'))
146
# test implicit --remember when no parent set, this merge conflicts
147
self.build_tree(['d'])
149
out = self.runbzr('merge ../branch_a', retcode=3)
150
self.assertEquals(out,
151
('','bzr: ERROR: Working tree has uncommitted changes.\n'))
152
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
153
# test implicit --remember after resolving conflict
154
tree_b.commit('commit d')
155
out, err = self.runbzr('merge')
157
base = urlutils.local_path_from_url(branch_a.base)
158
self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
159
self.assertEquals(err, 'All changes applied successfully.\n')
160
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
161
# re-open tree as external runbzr modified it
162
tree_b = branch_b.bzrdir.open_workingtree()
163
tree_b.commit('merge branch_a')
164
# test explicit --remember
165
out, err = self.runbzr('merge ../branch_c --remember')
166
self.assertEquals(out, '')
167
self.assertEquals(err, 'All changes applied successfully.\n')
168
self.assertEquals(abspath(branch_b.get_parent()),
169
abspath(branch_c.bzrdir.root_transport.base))
170
# re-open tree as external runbzr modified it
171
tree_b = branch_b.bzrdir.open_workingtree()
172
tree_b.commit('merge branch_c')