~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_merge.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-07-16 20:21:22 UTC
  • mfrom: (2617.1.4 skip_pyrex)
  • Revision ID: pqm@pqm.ubuntu.com-20070716202122-hs4anrki1xzulugo
(John Arbash Meinel) Skip pyrex dependencies if we can't build, rather than failing

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
#
 
17
# Author: Aaron Bentley <aaron.bentley@utoronto.ca>
 
18
 
 
19
"""Black-box tests for bzr merge.
 
20
"""
 
21
 
 
22
import os
 
23
 
 
24
from bzrlib.branch import Branch
 
25
from bzrlib.bzrdir import BzrDir
 
26
from bzrlib.conflicts import ConflictList, ContentsConflict
 
27
from bzrlib.osutils import abspath, file_kind
 
28
from bzrlib.tests.blackbox import ExternalBase
 
29
import bzrlib.urlutils as urlutils
 
30
from bzrlib.workingtree import WorkingTree
 
31
 
 
32
 
 
33
class TestMerge(ExternalBase):
 
34
 
 
35
    def example_branch(test):
 
36
        test.run_bzr('init')
 
37
        file('hello', 'wt').write('foo')
 
38
        test.run_bzr('add hello')
 
39
        test.run_bzr('commit -m setup hello')
 
40
        file('goodbye', 'wt').write('baz')
 
41
        test.run_bzr('add goodbye')
 
42
        test.run_bzr('commit -m setup goodbye')
 
43
 
 
44
    def test_merge_reprocess(self):
 
45
        d = BzrDir.create_standalone_workingtree('.')
 
46
        d.commit('h')
 
47
        self.run_bzr('merge . --reprocess --merge-type weave')
 
48
 
 
49
    def test_merge(self):
 
50
        from bzrlib.branch import Branch
 
51
        
 
52
        os.mkdir('a')
 
53
        os.chdir('a')
 
54
        self.example_branch()
 
55
        ancestor = Branch.open('.').revno()
 
56
        os.chdir('..')
 
57
        self.run_bzr('branch a b')
 
58
        os.chdir('b')
 
59
        file('goodbye', 'wt').write('quux')
 
60
        self.run_bzr(['commit',  '-m',  "more u's are always good"])
 
61
 
 
62
        os.chdir('../a')
 
63
        file('hello', 'wt').write('quuux')
 
64
        # We can't merge when there are in-tree changes
 
65
        self.run_bzr('merge ../b', retcode=3)
 
66
        a = WorkingTree.open('.')
 
67
        a_tip = a.commit("Like an epidemic of u's")
 
68
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type blooof',
 
69
                    retcode=3)
 
70
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type merge3')
 
71
        self.run_bzr('revert --no-backup')
 
72
        self.run_bzr('merge ../b -r last:1..last:1 --merge-type weave')
 
73
        self.run_bzr('revert --no-backup')
 
74
        self.run_bzr('merge ../b -r last:1..last:1 --reprocess')
 
75
        self.run_bzr('revert --no-backup')
 
76
        self.run_bzr('merge ../b -r last:1')
 
77
        self.check_file_contents('goodbye', 'quux')
 
78
        # Merging a branch pulls its revision into the tree
 
79
        b = Branch.open('../b')
 
80
        b_tip = b.last_revision()
 
81
        self.failUnless(a.branch.repository.has_revision(b_tip))
 
82
        self.assertEqual([a_tip, b_tip], a.get_parent_ids())
 
83
        self.run_bzr('revert --no-backup')
 
84
        out, err = self.run_bzr('merge -r revno:1:./hello', retcode=3)
 
85
        self.assertTrue("Not a branch" in err)
 
86
        self.run_bzr('merge -r revno:%d:./..revno:%d:../b'
 
87
                    %(ancestor,b.revno()))
 
88
        self.assertEquals(a.get_parent_ids(), 
 
89
                          [a.branch.last_revision(), b.last_revision()])
 
90
        self.check_file_contents('goodbye', 'quux')
 
91
        self.run_bzr('revert --no-backup')
 
92
        self.run_bzr('merge -r revno:%d:../b'%b.revno())
 
93
        self.assertEquals(a.get_parent_ids(),
 
94
                          [a.branch.last_revision(), b.last_revision()])
 
95
        a_tip = a.commit('merged')
 
96
        self.run_bzr('merge ../b -r last:1')
 
97
        self.assertEqual([a_tip], a.get_parent_ids())
 
98
 
 
99
    def test_merge_with_missing_file(self):
 
100
        """Merge handles missing file conflicts"""
 
101
        os.mkdir('a')
 
102
        os.chdir('a')
 
103
        os.mkdir('sub')
 
104
        print >> file('sub/a.txt', 'wb'), "hello"
 
105
        print >> file('b.txt', 'wb'), "hello"
 
106
        print >> file('sub/c.txt', 'wb'), "hello"
 
107
        self.run_bzr('init')
 
108
        self.run_bzr('add')
 
109
        self.run_bzr(['commit', '-m', 'added a'])
 
110
        self.run_bzr('branch . ../b')
 
111
        print >> file('sub/a.txt', 'ab'), "there"
 
112
        print >> file('b.txt', 'ab'), "there"
 
113
        print >> file('sub/c.txt', 'ab'), "there"
 
114
        self.run_bzr(['commit', '-m', 'Added there'])
 
115
        os.unlink('sub/a.txt')
 
116
        os.unlink('sub/c.txt')
 
117
        os.rmdir('sub')
 
118
        os.unlink('b.txt')
 
119
        self.run_bzr(['commit', '-m', 'Removed a.txt'])
 
120
        os.chdir('../b')
 
121
        print >> file('sub/a.txt', 'ab'), "something"
 
122
        print >> file('b.txt', 'ab'), "something"
 
123
        print >> file('sub/c.txt', 'ab'), "something"
 
124
        self.run_bzr(['commit', '-m', 'Modified a.txt'])
 
125
        self.run_bzr('merge ../a/', retcode=1)
 
126
        self.assert_(os.path.exists('sub/a.txt.THIS'))
 
127
        self.assert_(os.path.exists('sub/a.txt.BASE'))
 
128
        os.chdir('../a')
 
129
        self.run_bzr('merge ../b/', retcode=1)
 
130
        self.assert_(os.path.exists('sub/a.txt.OTHER'))
 
131
        self.assert_(os.path.exists('sub/a.txt.BASE'))
 
132
 
 
133
    def test_merge_remember(self):
 
134
        """Merge changes from one branch to another and test parent location."""
 
135
        tree_a = self.make_branch_and_tree('branch_a')
 
136
        branch_a = tree_a.branch
 
137
        self.build_tree(['branch_a/a'])
 
138
        tree_a.add('a')
 
139
        tree_a.commit('commit a')
 
140
        branch_b = branch_a.bzrdir.sprout('branch_b').open_branch()
 
141
        tree_b = branch_b.bzrdir.open_workingtree()
 
142
        branch_c = branch_a.bzrdir.sprout('branch_c').open_branch()
 
143
        tree_c = branch_c.bzrdir.open_workingtree()
 
144
        self.build_tree(['branch_a/b'])
 
145
        tree_a.add('b')
 
146
        tree_a.commit('commit b')
 
147
        self.build_tree(['branch_c/c'])
 
148
        tree_c.add('c')
 
149
        tree_c.commit('commit c')
 
150
        # reset parent
 
151
        parent = branch_b.get_parent()
 
152
        branch_b.set_parent(None)
 
153
        self.assertEqual(None, branch_b.get_parent())
 
154
        # test merge for failure without parent set
 
155
        os.chdir('branch_b')
 
156
        out = self.run_bzr('merge', retcode=3)
 
157
        self.assertEquals(out,
 
158
                ('','bzr: ERROR: No location specified or remembered\n'))
 
159
        # test implicit --remember when no parent set, this merge conflicts
 
160
        self.build_tree(['d'])
 
161
        tree_b.add('d')
 
162
        out = self.run_bzr('merge ../branch_a', retcode=3)
 
163
        self.assertEquals(out,
 
164
                ('','bzr: ERROR: Working tree has uncommitted changes.\n'))
 
165
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
 
166
        # test implicit --remember after resolving conflict
 
167
        tree_b.commit('commit d')
 
168
        out, err = self.run_bzr('merge')
 
169
        
 
170
        base = urlutils.local_path_from_url(branch_a.base)
 
171
        self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
 
172
        self.assertEquals(err, '+N  b\nAll changes applied successfully.\n')
 
173
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
 
174
        # re-open tree as external run_bzr modified it
 
175
        tree_b = branch_b.bzrdir.open_workingtree()
 
176
        tree_b.commit('merge branch_a')
 
177
        # test explicit --remember
 
178
        out, err = self.run_bzr('merge ../branch_c --remember')
 
179
        self.assertEquals(out, '')
 
180
        self.assertEquals(err, '+N  c\nAll changes applied successfully.\n')
 
181
        self.assertEquals(abspath(branch_b.get_parent()),
 
182
                          abspath(branch_c.bzrdir.root_transport.base))
 
183
        # re-open tree as external run_bzr modified it
 
184
        tree_b = branch_b.bzrdir.open_workingtree()
 
185
        tree_b.commit('merge branch_c')
 
186
 
 
187
    def test_merge_bundle(self):
 
188
        from bzrlib.testament import Testament
 
189
        tree_a = self.make_branch_and_tree('branch_a')
 
190
        f = file('branch_a/a', 'wb')
 
191
        f.write('hello')
 
192
        f.close()
 
193
        tree_a.add('a')
 
194
        tree_a.commit('message')
 
195
 
 
196
        tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
 
197
        f = file('branch_a/a', 'wb')
 
198
        f.write('hey there')
 
199
        f.close()
 
200
        tree_a.commit('message')
 
201
 
 
202
        f = file('branch_b/a', 'wb')
 
203
        f.write('goodbye')
 
204
        f.close()
 
205
        tree_b.commit('message')
 
206
        os.chdir('branch_b')
 
207
        file('../bundle', 'wb').write(self.run_bzr('bundle ../branch_a')[0])
 
208
        os.chdir('../branch_a')
 
209
        self.run_bzr('merge ../bundle', retcode=1)
 
210
        testament_a = Testament.from_revision(tree_a.branch.repository,
 
211
                                              tree_b.get_parent_ids()[0])
 
212
        testament_b = Testament.from_revision(tree_b.branch.repository,
 
213
                                              tree_b.get_parent_ids()[0])
 
214
        self.assertEqualDiff(testament_a.as_text(),
 
215
                         testament_b.as_text())
 
216
        tree_a.set_conflicts(ConflictList())
 
217
        tree_a.commit('message')
 
218
        # it is legal to attempt to merge an already-merged bundle
 
219
        output = self.run_bzr('merge ../bundle')[1]
 
220
        # but it does nothing
 
221
        self.assertFalse(tree_a.changes_from(tree_a.basis_tree()).has_changed())
 
222
        self.assertEqual('Nothing to do.\n', output)
 
223
 
 
224
    def test_merge_uncommitted(self):
 
225
        """Check that merge --uncommitted behaves properly"""
 
226
        tree_a = self.make_branch_and_tree('a')
 
227
        self.build_tree(['a/file_1', 'a/file_2'])
 
228
        tree_a.add(['file_1', 'file_2'])
 
229
        tree_a.commit('commit 1')
 
230
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
 
231
        self.failUnlessExists('b/file_1')
 
232
        tree_a.rename_one('file_1', 'file_i')
 
233
        tree_a.commit('commit 2')
 
234
        tree_a.rename_one('file_2', 'file_ii')
 
235
        ## os.chdir('b')
 
236
        self.run_bzr('merge a --uncommitted -d b')
 
237
        self.failUnlessExists('b/file_1')
 
238
        self.failUnlessExists('b/file_ii')
 
239
        tree_b.revert([])
 
240
        self.run_bzr_error(('Cannot use --uncommitted and --revision',),
 
241
                           'merge /a --uncommitted -r1 -d b')
 
242
 
 
243
    def pullable_branch(self):
 
244
        os.mkdir('a')
 
245
        os.chdir('a')
 
246
        self.example_branch()
 
247
        os.chdir('..')
 
248
        self.run_bzr('branch a b')
 
249
        os.chdir('b')
 
250
        file('goodbye', 'wt').write('quux')
 
251
        self.run_bzr(['commit', '-m', "mode u's are always good"])
 
252
        os.chdir('../a')
 
253
 
 
254
    def pullable_branch(self):
 
255
        tree_a = self.make_branch_and_tree('a')
 
256
        self.build_tree(['a/file'])
 
257
        tree_a.add(['file'])
 
258
        self.id1 = tree_a.commit('commit 1')
 
259
        
 
260
        tree_b = self.make_branch_and_tree('b')
 
261
        tree_b.pull(tree_a.branch)
 
262
        file('b/file', 'wb').write('foo')
 
263
        self.id2 = tree_b.commit('commit 2')
 
264
 
 
265
    def test_merge_pull(self):
 
266
        self.pullable_branch()
 
267
        os.chdir('a')
 
268
        (out, err) = self.run_bzr('merge --pull ../b')
 
269
        self.assertContainsRe(err, 'Now on revision 2\\.')
 
270
        tree_a = WorkingTree.open('.')
 
271
        self.assertEqual([self.id2], tree_a.get_parent_ids())
 
272
 
 
273
    def test_merge_kind_change(self):
 
274
        tree_a = self.make_branch_and_tree('tree_a')
 
275
        self.build_tree_contents([('tree_a/file', 'content_1')])
 
276
        tree_a.add('file', 'file-id')
 
277
        tree_a.commit('added file')
 
278
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
 
279
        os.unlink('tree_a/file')
 
280
        self.build_tree(['tree_a/file/'])
 
281
        tree_a.commit('changed file to directory')
 
282
        os.chdir('tree_b')
 
283
        self.run_bzr('merge ../tree_a')
 
284
        self.assertEqual('directory', file_kind('file'))
 
285
        tree_b.revert([])
 
286
        self.assertEqual('file', file_kind('file'))
 
287
        self.build_tree_contents([('file', 'content_2')])
 
288
        tree_b.commit('content change')
 
289
        self.run_bzr('merge ../tree_a', retcode=1)
 
290
        self.assertEqual(tree_b.conflicts(),
 
291
                         [ContentsConflict('file', file_id='file-id')])