~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

Deprecate compare_trees and move its body to InterTree.changes_from.

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
        os.chdir('..')
 
56
        self.runbzr('branch a b')
 
57
        os.chdir('b')
 
58
        file('goodbye', 'wt').write('quux')
 
59
        self.runbzr(['commit',  '-m',  "more u's are always good"])
 
60
 
 
61
        os.chdir('../a')
 
62
        file('hello', 'wt').write('quuux')
 
63
        # We can't merge when there are in-tree changes
 
64
        self.runbzr('merge ../b', retcode=3)
 
65
        self.runbzr(['commit', '-m', "Like an epidemic of u's"])
 
66
        self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
 
67
                    retcode=3)
 
68
        self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
 
69
        self.runbzr('revert --no-backup')
 
70
        self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
 
71
        self.runbzr('revert --no-backup')
 
72
        self.runbzr('merge ../b -r last:1..last:1 --reprocess')
 
73
        self.runbzr('revert --no-backup')
 
74
        self.runbzr('merge ../b -r last:1')
 
75
        self.check_file_contents('goodbye', 'quux')
 
76
        # Merging a branch pulls its revision into the tree
 
77
        a = WorkingTree.open('.')
 
78
        b = Branch.open('../b')
 
79
        a.branch.repository.get_revision_xml(b.last_revision())
 
80
        self.log('pending merges: %s', a.pending_merges())
 
81
        self.assertEquals(a.pending_merges(),
 
82
                          [b.last_revision()])
 
83
        self.runbzr('commit -m merged')
 
84
        self.runbzr('merge ../b -r last:1')
 
85
        self.assertEqual(a.pending_merges(), [])
 
86
 
 
87
    def test_merge_with_missing_file(self):
 
88
        """Merge handles missing file conflicts"""
 
89
        os.mkdir('a')
 
90
        os.chdir('a')
 
91
        os.mkdir('sub')
 
92
        print >> file('sub/a.txt', 'wb'), "hello"
 
93
        print >> file('b.txt', 'wb'), "hello"
 
94
        print >> file('sub/c.txt', 'wb'), "hello"
 
95
        self.runbzr('init')
 
96
        self.runbzr('add')
 
97
        self.runbzr(('commit', '-m', 'added a'))
 
98
        self.runbzr('branch . ../b')
 
99
        print >> file('sub/a.txt', 'ab'), "there"
 
100
        print >> file('b.txt', 'ab'), "there"
 
101
        print >> file('sub/c.txt', 'ab'), "there"
 
102
        self.runbzr(('commit', '-m', 'Added there'))
 
103
        os.unlink('sub/a.txt')
 
104
        os.unlink('sub/c.txt')
 
105
        os.rmdir('sub')
 
106
        os.unlink('b.txt')
 
107
        self.runbzr(('commit', '-m', 'Removed a.txt'))
 
108
        os.chdir('../b')
 
109
        print >> file('sub/a.txt', 'ab'), "something"
 
110
        print >> file('b.txt', 'ab'), "something"
 
111
        print >> file('sub/c.txt', 'ab'), "something"
 
112
        self.runbzr(('commit', '-m', 'Modified a.txt'))
 
113
        self.runbzr('merge ../a/', retcode=1)
 
114
        self.assert_(os.path.exists('sub/a.txt.THIS'))
 
115
        self.assert_(os.path.exists('sub/a.txt.BASE'))
 
116
        os.chdir('../a')
 
117
        self.runbzr('merge ../b/', retcode=1)
 
118
        self.assert_(os.path.exists('sub/a.txt.OTHER'))
 
119
        self.assert_(os.path.exists('sub/a.txt.BASE'))
 
120
 
 
121
    def test_merge_remember(self):
 
122
        """Merge changes from one branch to another and test parent location."""
 
123
        tree_a = self.make_branch_and_tree('branch_a')
 
124
        branch_a = tree_a.branch
 
125
        self.build_tree(['branch_a/a'])
 
126
        tree_a.add('a')
 
127
        tree_a.commit('commit a')
 
128
        branch_b = branch_a.bzrdir.sprout('branch_b').open_branch()
 
129
        tree_b = branch_b.bzrdir.open_workingtree()
 
130
        branch_c = branch_a.bzrdir.sprout('branch_c').open_branch()
 
131
        tree_c = branch_c.bzrdir.open_workingtree()
 
132
        self.build_tree(['branch_a/b'])
 
133
        tree_a.add('b')
 
134
        tree_a.commit('commit b')
 
135
        self.build_tree(['branch_c/c'])
 
136
        tree_c.add('c')
 
137
        tree_c.commit('commit c')
 
138
        # reset parent
 
139
        parent = branch_b.get_parent()
 
140
        branch_b.set_parent(None)
 
141
        self.assertEqual(None, branch_b.get_parent())
 
142
        # test merge for failure without parent set
 
143
        os.chdir('branch_b')
 
144
        out = self.runbzr('merge', retcode=3)
 
145
        self.assertEquals(out,
 
146
                ('','bzr: ERROR: No location specified or remembered\n'))
 
147
        # test implicit --remember when no parent set, this merge conflicts
 
148
        self.build_tree(['d'])
 
149
        tree_b.add('d')
 
150
        out = self.runbzr('merge ../branch_a', retcode=3)
 
151
        self.assertEquals(out,
 
152
                ('','bzr: ERROR: Working tree has uncommitted changes.\n'))
 
153
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
 
154
        # test implicit --remember after resolving conflict
 
155
        tree_b.commit('commit d')
 
156
        out, err = self.runbzr('merge')
 
157
        
 
158
        base = urlutils.local_path_from_url(branch_a.base)
 
159
        self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
 
160
        self.assertEquals(err, 'All changes applied successfully.\n')
 
161
        self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
 
162
        # re-open tree as external runbzr modified it
 
163
        tree_b = branch_b.bzrdir.open_workingtree()
 
164
        tree_b.commit('merge branch_a')
 
165
        # test explicit --remember
 
166
        out, err = self.runbzr('merge ../branch_c --remember')
 
167
        self.assertEquals(out, '')
 
168
        self.assertEquals(err, 'All changes applied successfully.\n')
 
169
        self.assertEquals(abspath(branch_b.get_parent()),
 
170
                          abspath(branch_c.bzrdir.root_transport.base))
 
171
        # re-open tree as external runbzr modified it
 
172
        tree_b = branch_b.bzrdir.open_workingtree()
 
173
        tree_b.commit('merge branch_c')
 
174
 
 
175
    def test_merge_bundle(self):
 
176
        from bzrlib.testament import Testament
 
177
        tree_a = self.make_branch_and_tree('branch_a')
 
178
        f = file('branch_a/a', 'wb')
 
179
        f.write('hello')
 
180
        f.close()
 
181
        tree_a.add('a')
 
182
        tree_a.commit('message')
 
183
 
 
184
        tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
 
185
        f = file('branch_a/a', 'wb')
 
186
        f.write('hey there')
 
187
        f.close()
 
188
        tree_a.commit('message')
 
189
 
 
190
        f = file('branch_b/a', 'wb')
 
191
        f.write('goodbye')
 
192
        f.close()
 
193
        tree_b.commit('message')
 
194
        os.chdir('branch_b')
 
195
        file('../bundle', 'wb').write(self.runbzr('bundle ../branch_a')[0])
 
196
        os.chdir('../branch_a')
 
197
        self.runbzr('merge ../bundle', retcode=1)
 
198
        testament_a = Testament.from_revision(tree_a.branch.repository, 
 
199
                                              tree_b.last_revision())
 
200
        testament_b = Testament.from_revision(tree_b.branch.repository,
 
201
                                              tree_b.last_revision())
 
202
        self.assertEqualDiff(testament_a.as_text(),
 
203
                         testament_b.as_text())
 
204
        tree_a.set_conflicts(ConflictList())
 
205
        tree_a.commit('message')
 
206
        # it is legal to attempt to merge an already-merged bundle
 
207
        output = self.runbzr('merge ../bundle')[1]
 
208
        # but it does nothing
 
209
        self.assertFalse(tree_a.changes_from(tree_a.basis_tree()).has_changed())
 
210
        self.assertEqual('Nothing to do.\n', output)