1
# Copyright (C) 2007-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests for breezy.switch."""
32
class TestSwitch(tests.TestCaseWithTransport):
35
super(TestSwitch, self).setUp()
36
self.lightweight = True
39
def _master_if_present(branch):
40
master = branch.get_master_branch()
46
def _setup_tree(self):
47
tree = self.make_branch_and_tree('branch-1')
48
self.build_tree(['branch-1/file-1'])
53
def _setup_uncommitted(self, same_revision=False):
54
tree = self._setup_tree()
55
to_branch = tree.controldir.sprout('branch-2').open_branch()
56
self.build_tree(['branch-1/file-2'])
61
checkout = tree.branch.create_checkout('checkout',
62
lightweight=self.lightweight)
63
self.build_tree(['checkout/file-3'])
64
checkout.add('file-3')
65
return checkout, to_branch
67
def test_switch_store_uncommitted(self):
68
"""Test switch updates tree and stores uncommitted changes."""
69
checkout, to_branch = self._setup_uncommitted()
70
self.assertPathDoesNotExist('checkout/file-1')
71
self.assertPathExists('checkout/file-2')
72
switch.switch(checkout.controldir, to_branch, store_uncommitted=True)
73
self.assertPathExists('checkout/file-1')
74
self.assertPathDoesNotExist('checkout/file-2')
75
self.assertPathDoesNotExist('checkout/file-3')
77
def test_switch_restore_uncommitted(self):
78
"""Test switch updates tree and restores uncommitted changes."""
79
checkout, to_branch = self._setup_uncommitted()
80
old_branch = self._master_if_present(checkout.branch)
81
self.assertPathDoesNotExist('checkout/file-1')
82
self.assertPathExists('checkout/file-2')
83
self.assertPathExists('checkout/file-3')
84
switch.switch(checkout.controldir, to_branch, store_uncommitted=True)
85
checkout = workingtree.WorkingTree.open('checkout')
86
switch.switch(checkout.controldir, old_branch, store_uncommitted=True)
87
self.assertPathDoesNotExist('checkout/file-1')
88
self.assertPathExists('checkout/file-2')
89
self.assertPathExists('checkout/file-3')
91
def test_switch_restore_uncommitted_same_revision(self):
92
"""Test switch updates tree and restores uncommitted changes."""
93
checkout, to_branch = self._setup_uncommitted(same_revision=True)
94
old_branch = self._master_if_present(checkout.branch)
95
switch.switch(checkout.controldir, to_branch, store_uncommitted=True)
96
checkout = workingtree.WorkingTree.open('checkout')
97
switch.switch(checkout.controldir, old_branch, store_uncommitted=True)
98
self.assertPathExists('checkout/file-3')
100
def test_switch_updates(self):
101
"""Test switch updates tree and keeps uncommitted changes."""
102
checkout, to_branch = self._setup_uncommitted()
103
self.assertPathDoesNotExist('checkout/file-1')
104
self.assertPathExists('checkout/file-2')
105
switch.switch(checkout.controldir, to_branch)
106
self.assertPathExists('checkout/file-1')
107
self.assertPathDoesNotExist('checkout/file-2')
108
self.assertPathExists('checkout/file-3')
110
def test_switch_after_branch_moved(self):
111
"""Test switch after the branch is moved."""
112
tree = self._setup_tree()
113
checkout = tree.branch.create_checkout('checkout',
114
lightweight=self.lightweight)
115
self.build_tree(['branch-1/file-2'])
117
tree.remove('file-1')
119
self.build_tree(['checkout/file-3'])
120
checkout.add('file-3')
121
# rename the branch on disk, the checkout object is now invalid.
122
os.rename('branch-1', 'branch-2')
123
to_branch = branch.Branch.open('branch-2')
124
# Check fails without --force
125
err = self.assertRaises(
126
(errors.BzrCommandError, errors.NotBranchError),
127
switch.switch, checkout.controldir, to_branch)
128
if isinstance(err, errors.BzrCommandError):
129
self.assertContainsRe(str(err),
130
'Unable to connect to current master branch .*'
131
'To switch anyway, use --force.')
132
switch.switch(checkout.controldir, to_branch, force=True)
133
self.assertPathDoesNotExist('checkout/file-1')
134
self.assertPathExists('checkout/file-2')
135
self.assertPathExists('checkout/file-3')
137
def test_switch_when_pending_merges(self):
138
"""Test graceful failure if pending merges are outstanding."""
139
# Create 2 branches and a checkout
140
tree = self._setup_tree()
141
tree2 = tree.controldir.sprout('branch-2').open_workingtree()
142
checkout = tree.branch.create_checkout('checkout',
143
lightweight=self.lightweight)
144
# Change tree2 and merge it into the checkout without committing
145
self.build_tree(['branch-2/file-2'])
148
checkout.merge_from_branch(tree2.branch)
149
# Check the error reporting is as expected
150
err = self.assertRaises(errors.BzrCommandError,
151
switch.switch, checkout.controldir, tree2.branch)
152
self.assertContainsRe(str(err),
153
"Pending merges must be committed or reverted before using switch")
155
def test_switch_with_revision(self):
156
"""Test switch when a revision is given."""
157
# Create a tree with 2 revisions
158
tree = self.make_branch_and_tree('branch-1')
159
self.build_tree(['branch-1/file-1'])
161
tree.commit(rev_id=b'rev1', message='rev1')
162
self.build_tree(['branch-1/file-2'])
164
tree.commit(rev_id=b'rev2', message='rev2')
165
# Check it out and switch to revision 1
166
checkout = tree.branch.create_checkout('checkout',
167
lightweight=self.lightweight)
168
switch.switch(checkout.controldir, tree.branch, revision_id=b"rev1")
169
self.assertPathExists('checkout/file-1')
170
self.assertPathDoesNotExist('checkout/file-2')
172
def test_switch_changing_root_id(self):
173
tree = self._setup_tree()
174
tree2 = self.make_branch_and_tree('tree-2')
175
tree2.set_root_id(b'custom-root-id')
176
self.build_tree(['tree-2/file-2'])
177
tree2.add(['file-2'])
178
tree2.commit('rev1b')
179
checkout = tree.branch.create_checkout('checkout',
180
lightweight=self.lightweight)
181
switch.switch(checkout.controldir, tree2.branch)
182
self.assertEqual(b'custom-root-id', tree2.path2id(''))
184
def test_switch_configurable_file_merger(self):
185
class DummyMerger(_mod_merge.ConfigurableFileMerger):
188
_mod_merge.Merger.hooks.install_named_hook(
189
'merge_file_content', DummyMerger,
191
foo = self.make_branch('foo')
192
checkout = foo.create_checkout('checkout', lightweight=True)
193
self.build_tree_contents([('checkout/file', b'a')])
196
bar = foo.controldir.sprout('bar').open_workingtree()
197
self.build_tree_contents([('bar/file', b'b')])
199
self.build_tree_contents([('checkout/file', b'c')])
200
switch.switch(checkout.controldir, bar.branch)
203
class TestSwitchHeavyweight(TestSwitch):
206
super(TestSwitchHeavyweight, self).setUp()
207
self.lightweight = False
209
def test_switch_with_local_commits(self):
210
"""Test switch complains about local commits unless --force given."""
211
tree = self._setup_tree()
212
to_branch = tree.controldir.sprout('branch-2').open_branch()
213
self.build_tree(['branch-1/file-2'])
215
tree.remove('file-1')
217
checkout = tree.branch.create_checkout('checkout')
218
self.build_tree(['checkout/file-3'])
219
checkout.add('file-3')
220
checkout.commit(message='local only commit', local=True)
221
self.build_tree(['checkout/file-4'])
222
# Check the error reporting is as expected
223
err = self.assertRaises(errors.BzrCommandError,
224
switch.switch, checkout.controldir, to_branch)
225
self.assertContainsRe(str(err),
226
'Cannot switch as local commits found in the checkout.')
227
# Check all is ok when force is given
228
self.assertPathDoesNotExist('checkout/file-1')
229
self.assertPathExists('checkout/file-2')
230
switch.switch(checkout.controldir, to_branch, force=True)
231
self.assertPathExists('checkout/file-1')
232
self.assertPathDoesNotExist('checkout/file-2')
233
self.assertPathDoesNotExist('checkout/file-3')
234
self.assertPathExists('checkout/file-4')
235
# Check that the checkout is a true mirror of the bound branch
236
self.assertEqual(to_branch.last_revision_info(),
237
checkout.branch.last_revision_info())