~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2005-03-12 08:54:12 UTC
  • Revision ID: mbp@sourcefrog.net-20050312085412-13373aa129ccbad3
doc: notes on implementing codeville-style merge on
top of a weave; looks nice but opens a can of worms

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 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
27
 
from bzrlib.osutils import abspath
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.runbzr('init')
37
 
        file('hello', 'wt').write('foo')
38
 
        test.runbzr('add hello')
39
 
        test.runbzr('commit -m setup hello')
40
 
        file('goodbye', 'wt').write('baz')
41
 
        test.runbzr('add goodbye')
42
 
        test.runbzr('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.runbzr('branch a b')
58
 
        os.chdir('b')
59
 
        file('goodbye', 'wt').write('quux')
60
 
        self.runbzr(['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.runbzr('merge ../b', retcode=3)
66
 
        a = WorkingTree.open('.')
67
 
        a_tip = a.commit("Like an epidemic of u's")
68
 
        self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
69
 
                    retcode=3)
70
 
        self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
71
 
        self.runbzr('revert --no-backup')
72
 
        self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
73
 
        self.runbzr('revert --no-backup')
74
 
        self.runbzr('merge ../b -r last:1..last:1 --reprocess')
75
 
        self.runbzr('revert --no-backup')
76
 
        self.runbzr('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.runbzr('revert --no-backup')
84
 
        out, err = self.runbzr('merge -r revno:1:./hello', retcode=3)
85
 
        self.assertTrue("Not a branch" in err)
86
 
        self.runbzr('merge -r revno:%d:./..revno:%d:../b'
87
 
                    %(ancestor,b.revno()))
88
 
        self.assertEquals(a.pending_merges(), [b.last_revision()])
89
 
        self.check_file_contents('goodbye', 'quux')
90
 
        self.runbzr('revert --no-backup')
91
 
        self.runbzr('merge -r revno:%d:../b'%b.revno())
92
 
        self.assertEquals(a.pending_merges(),
93
 
                          [b.last_revision()])
94
 
        a_tip = a.commit('merged')
95
 
        self.runbzr('merge ../b -r last:1')
96
 
        self.assertEqual([a_tip], a.get_parent_ids())
97
 
 
98
 
    def test_merge_with_missing_file(self):
99
 
        """Merge handles missing file conflicts"""
100
 
        os.mkdir('a')
101
 
        os.chdir('a')
102
 
        os.mkdir('sub')
103
 
        print >> file('sub/a.txt', 'wb'), "hello"
104
 
        print >> file('b.txt', 'wb'), "hello"
105
 
        print >> file('sub/c.txt', 'wb'), "hello"
106
 
        self.runbzr('init')
107
 
        self.runbzr('add')
108
 
        self.runbzr(('commit', '-m', 'added a'))
109
 
        self.runbzr('branch . ../b')
110
 
        print >> file('sub/a.txt', 'ab'), "there"
111
 
        print >> file('b.txt', 'ab'), "there"
112
 
        print >> file('sub/c.txt', 'ab'), "there"
113
 
        self.runbzr(('commit', '-m', 'Added there'))
114
 
        os.unlink('sub/a.txt')
115
 
        os.unlink('sub/c.txt')
116
 
        os.rmdir('sub')
117
 
        os.unlink('b.txt')
118
 
        self.runbzr(('commit', '-m', 'Removed a.txt'))
119
 
        os.chdir('../b')
120
 
        print >> file('sub/a.txt', 'ab'), "something"
121
 
        print >> file('b.txt', 'ab'), "something"
122
 
        print >> file('sub/c.txt', 'ab'), "something"
123
 
        self.runbzr(('commit', '-m', 'Modified a.txt'))
124
 
        self.runbzr('merge ../a/', retcode=1)
125
 
        self.assert_(os.path.exists('sub/a.txt.THIS'))
126
 
        self.assert_(os.path.exists('sub/a.txt.BASE'))
127
 
        os.chdir('../a')
128
 
        self.runbzr('merge ../b/', retcode=1)
129
 
        self.assert_(os.path.exists('sub/a.txt.OTHER'))
130
 
        self.assert_(os.path.exists('sub/a.txt.BASE'))
131
 
 
132
 
    def test_merge_remember(self):
133
 
        """Merge changes from one branch to another and test parent location."""
134
 
        tree_a = self.make_branch_and_tree('branch_a')
135
 
        branch_a = tree_a.branch
136
 
        self.build_tree(['branch_a/a'])
137
 
        tree_a.add('a')
138
 
        tree_a.commit('commit a')
139
 
        branch_b = branch_a.bzrdir.sprout('branch_b').open_branch()
140
 
        tree_b = branch_b.bzrdir.open_workingtree()
141
 
        branch_c = branch_a.bzrdir.sprout('branch_c').open_branch()
142
 
        tree_c = branch_c.bzrdir.open_workingtree()
143
 
        self.build_tree(['branch_a/b'])
144
 
        tree_a.add('b')
145
 
        tree_a.commit('commit b')
146
 
        self.build_tree(['branch_c/c'])
147
 
        tree_c.add('c')
148
 
        tree_c.commit('commit c')
149
 
        # reset parent
150
 
        parent = branch_b.get_parent()
151
 
        branch_b.set_parent(None)
152
 
        self.assertEqual(None, branch_b.get_parent())
153
 
        # test merge for failure without parent set
154
 
        os.chdir('branch_b')
155
 
        out = self.runbzr('merge', retcode=3)
156
 
        self.assertEquals(out,
157
 
                ('','bzr: ERROR: No location specified or remembered\n'))
158
 
        # test implicit --remember when no parent set, this merge conflicts
159
 
        self.build_tree(['d'])
160
 
        tree_b.add('d')
161
 
        out = self.runbzr('merge ../branch_a', retcode=3)
162
 
        self.assertEquals(out,
163
 
                ('','bzr: ERROR: Working tree has uncommitted changes.\n'))
164
 
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
165
 
        # test implicit --remember after resolving conflict
166
 
        tree_b.commit('commit d')
167
 
        out, err = self.runbzr('merge')
168
 
        
169
 
        base = urlutils.local_path_from_url(branch_a.base)
170
 
        self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
171
 
        self.assertEquals(err, 'All changes applied successfully.\n')
172
 
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
173
 
        # re-open tree as external runbzr modified it
174
 
        tree_b = branch_b.bzrdir.open_workingtree()
175
 
        tree_b.commit('merge branch_a')
176
 
        # test explicit --remember
177
 
        out, err = self.runbzr('merge ../branch_c --remember')
178
 
        self.assertEquals(out, '')
179
 
        self.assertEquals(err, 'All changes applied successfully.\n')
180
 
        self.assertEquals(abspath(branch_b.get_parent()),
181
 
                          abspath(branch_c.bzrdir.root_transport.base))
182
 
        # re-open tree as external runbzr modified it
183
 
        tree_b = branch_b.bzrdir.open_workingtree()
184
 
        tree_b.commit('merge branch_c')
185
 
 
186
 
    def test_merge_bundle(self):
187
 
        from bzrlib.testament import Testament
188
 
        tree_a = self.make_branch_and_tree('branch_a')
189
 
        f = file('branch_a/a', 'wb')
190
 
        f.write('hello')
191
 
        f.close()
192
 
        tree_a.add('a')
193
 
        tree_a.commit('message')
194
 
 
195
 
        tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
196
 
        f = file('branch_a/a', 'wb')
197
 
        f.write('hey there')
198
 
        f.close()
199
 
        tree_a.commit('message')
200
 
 
201
 
        f = file('branch_b/a', 'wb')
202
 
        f.write('goodbye')
203
 
        f.close()
204
 
        tree_b.commit('message')
205
 
        os.chdir('branch_b')
206
 
        file('../bundle', 'wb').write(self.runbzr('bundle ../branch_a')[0])
207
 
        os.chdir('../branch_a')
208
 
        self.runbzr('merge ../bundle', retcode=1)
209
 
        testament_a = Testament.from_revision(tree_a.branch.repository,
210
 
                                              tree_b.get_parent_ids()[0])
211
 
        testament_b = Testament.from_revision(tree_b.branch.repository,
212
 
                                              tree_b.get_parent_ids()[0])
213
 
        self.assertEqualDiff(testament_a.as_text(),
214
 
                         testament_b.as_text())
215
 
        tree_a.set_conflicts(ConflictList())
216
 
        tree_a.commit('message')
217
 
        # it is legal to attempt to merge an already-merged bundle
218
 
        output = self.runbzr('merge ../bundle')[1]
219
 
        # but it does nothing
220
 
        self.assertFalse(tree_a.changes_from(tree_a.basis_tree()).has_changed())
221
 
        self.assertEqual('Nothing to do.\n', output)
222
 
 
223
 
    def test_merge_uncommitted(self):
224
 
        """Check that merge --uncommitted behaves properly"""
225
 
        tree_a = self.make_branch_and_tree('a')
226
 
        self.build_tree(['a/file_1', 'a/file_2'])
227
 
        tree_a.add(['file_1', 'file_2'])
228
 
        tree_a.commit('commit 1')
229
 
        tree_b = tree_a.bzrdir.sprout('b').open_workingtree()
230
 
        self.failUnlessExists('b/file_1')
231
 
        tree_a.rename_one('file_1', 'file_i')
232
 
        tree_a.commit('commit 2')
233
 
        tree_a.rename_one('file_2', 'file_ii')
234
 
        os.chdir('b')
235
 
        self.run_bzr('merge', '../a', '--uncommitted')
236
 
        self.failUnlessExists('file_1')
237
 
        self.failUnlessExists('file_ii')
238
 
        tree_b.revert([])
239
 
        self.run_bzr_error(('Cannot use --uncommitted and --revision',), 
240
 
                           'merge', '../a', '--uncommitted', '-r1')