1
# Copyright (C) 2007-2010 Canonical Ltd
2
# -*- coding: utf-8 -*-
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
"""Tests for the switch command of bzr."""
28
from bzrlib.workingtree import WorkingTree
29
from bzrlib.tests import (
30
TestCaseWithTransport,
33
from bzrlib.directory_service import directories
36
class TestSwitch(TestCaseWithTransport):
38
def _create_sample_tree(self):
39
tree = self.make_branch_and_tree('branch-1')
40
self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
47
def test_switch_up_to_date_light_checkout(self):
48
self.make_branch_and_tree('branch')
49
self.run_bzr('branch branch branch2')
50
self.run_bzr('checkout --lightweight branch checkout')
52
out, err = self.run_bzr('switch ../branch2')
53
self.assertContainsRe(err, 'Tree is up to date at revision 0.\n')
54
self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
55
self.assertEqual('', out)
57
def test_switch_out_of_date_light_checkout(self):
58
self.make_branch_and_tree('branch')
59
self.run_bzr('branch branch branch2')
60
self.build_tree(['branch2/file'])
61
self.run_bzr('add branch2/file')
62
self.run_bzr('commit -m add-file branch2')
63
self.run_bzr('checkout --lightweight branch checkout')
65
out, err = self.run_bzr('switch ../branch2')
66
#self.assertContainsRe(err, '\+N file')
67
self.assertContainsRe(err, 'Updated to revision 1.\n')
68
self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
69
self.assertEqual('', out)
71
def _test_switch_nick(self, lightweight):
72
"""Check that the nick gets switched too."""
73
tree1 = self.make_branch_and_tree('branch1')
74
tree2 = self.make_branch_and_tree('branch2')
75
tree2.pull(tree1.branch)
76
checkout = tree1.branch.create_checkout('checkout',
77
lightweight=lightweight)
78
self.assertEqual(checkout.branch.nick, tree1.branch.nick)
79
self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
81
self.run_bzr('switch branch2', working_dir='checkout')
83
# we need to get the tree again, otherwise we don't get the new branch
84
checkout = WorkingTree.open('checkout')
85
self.assertEqual(checkout.branch.nick, tree2.branch.nick)
86
self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
89
def test_switch_nick(self):
90
self._test_switch_nick(lightweight=False)
92
def test_switch_nick_lightweight(self):
93
self._test_switch_nick(lightweight=True)
95
def _test_switch_explicit_nick(self, lightweight):
96
"""Check that the nick gets switched too."""
97
tree1 = self.make_branch_and_tree('branch1')
98
tree2 = self.make_branch_and_tree('branch2')
99
tree2.pull(tree1.branch)
100
checkout = tree1.branch.create_checkout('checkout',
101
lightweight=lightweight)
102
self.assertEqual(checkout.branch.nick, tree1.branch.nick)
103
checkout.branch.nick = "explicit_nick"
104
self.assertEqual(checkout.branch.nick, "explicit_nick")
105
self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
107
self.run_bzr('switch branch2', working_dir='checkout')
109
# we need to get the tree again, otherwise we don't get the new branch
110
checkout = WorkingTree.open('checkout')
111
self.assertEqual(checkout.branch.nick, tree2.branch.nick)
112
self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
115
def test_switch_explicit_nick(self):
116
self._test_switch_explicit_nick(lightweight=False)
118
def test_switch_explicit_nick_lightweight(self):
119
self._test_switch_explicit_nick(lightweight=True)
121
def test_switch_finds_relative_branch(self):
122
"""Switch will find 'foo' relative to the branch the checkout is of."""
123
self.build_tree(['repo/'])
124
tree1 = self.make_branch_and_tree('repo/brancha')
126
tree2 = self.make_branch_and_tree('repo/branchb')
127
tree2.pull(tree1.branch)
128
branchb_id = tree2.commit('bar')
129
checkout = tree1.branch.create_checkout('checkout', lightweight=True)
130
self.run_bzr(['switch', 'branchb'], working_dir='checkout')
131
self.assertEqual(branchb_id, checkout.last_revision())
132
checkout = checkout.bzrdir.open_workingtree()
133
self.assertEqual(tree2.branch.base, checkout.branch.base)
135
def test_switch_finds_relative_bound_branch(self):
136
"""Using switch on a heavy checkout should find master sibling
138
The behaviour of lighweight and heavy checkouts should be
139
consistent when using the convenient "switch to sibling" feature
140
Both should switch to a sibling of the branch
141
they are bound to, and not a sibling of themself"""
143
self.build_tree(['repo/',
145
tree1 = self.make_branch_and_tree('repo/brancha')
147
tree2 = self.make_branch_and_tree('repo/branchb')
148
tree2.pull(tree1.branch)
149
branchb_id = tree2.commit('bar')
150
checkout = tree1.branch.create_checkout('heavyco/a', lightweight=False)
151
self.run_bzr(['switch', 'branchb'], working_dir='heavyco/a')
152
self.assertEqual(branchb_id, checkout.last_revision())
153
self.assertEqual(tree2.branch.base, checkout.branch.get_bound_location())
155
def test_switch_revision(self):
156
tree = self._create_sample_tree()
157
checkout = tree.branch.create_checkout('checkout', lightweight=True)
158
self.run_bzr(['switch', 'branch-1', '-r1'], working_dir='checkout')
159
self.assertPathExists('checkout/file-1')
160
self.assertPathDoesNotExist('checkout/file-2')
162
def test_switch_only_revision(self):
163
tree = self._create_sample_tree()
164
checkout = tree.branch.create_checkout('checkout', lightweight=True)
165
self.assertPathExists('checkout/file-1')
166
self.assertPathExists('checkout/file-2')
167
self.run_bzr(['switch', '-r1'], working_dir='checkout')
168
self.assertPathExists('checkout/file-1')
169
self.assertPathDoesNotExist('checkout/file-2')
170
# Check that we don't accept a range
172
['bzr switch --revision takes exactly one revision identifier'],
173
['switch', '-r0..2'], working_dir='checkout')
175
def prepare_lightweight_switch(self):
176
branch = self.make_branch('branch')
177
branch.create_checkout('tree', lightweight=True)
178
osutils.rename('branch', 'branch1')
180
def test_switch_lightweight_after_branch_moved(self):
181
self.prepare_lightweight_switch()
182
self.run_bzr('switch --force ../branch1', working_dir='tree')
183
branch_location = WorkingTree.open('tree').branch.base
184
self.assertEndsWith(branch_location, 'branch1/')
186
def test_switch_lightweight_after_branch_moved_relative(self):
187
self.prepare_lightweight_switch()
188
self.run_bzr('switch --force branch1', working_dir='tree')
189
branch_location = WorkingTree.open('tree').branch.base
190
self.assertEndsWith(branch_location, 'branch1/')
192
def test_create_branch_no_branch(self):
193
self.prepare_lightweight_switch()
194
self.run_bzr_error(['cannot create branch without source branch'],
195
'switch --create-branch ../branch2', working_dir='tree')
197
def test_create_branch(self):
198
branch = self.make_branch('branch')
199
tree = branch.create_checkout('tree', lightweight=True)
200
tree.commit('one', rev_id='rev-1')
201
self.run_bzr('switch --create-branch ../branch2', working_dir='tree')
202
tree = WorkingTree.open('tree')
203
self.assertEndsWith(tree.branch.base, '/branch2/')
205
def test_create_branch_local(self):
206
branch = self.make_branch('branch')
207
tree = branch.create_checkout('tree', lightweight=True)
208
tree.commit('one', rev_id='rev-1')
209
self.run_bzr('switch --create-branch branch2', working_dir='tree')
210
tree = WorkingTree.open('tree')
211
# The new branch should have been created at the same level as
212
# 'branch', because we did not have a '/' segment
213
self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
215
def test_create_branch_short_name(self):
216
branch = self.make_branch('branch')
217
tree = branch.create_checkout('tree', lightweight=True)
218
tree.commit('one', rev_id='rev-1')
219
self.run_bzr('switch -b branch2', working_dir='tree')
220
tree = WorkingTree.open('tree')
221
# The new branch should have been created at the same level as
222
# 'branch', because we did not have a '/' segment
223
self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
225
def test_create_branch_directory_services(self):
226
branch = self.make_branch('branch')
227
tree = branch.create_checkout('tree', lightweight=True)
228
class FooLookup(object):
229
def look_up(self, name, url):
231
directories.register('foo:', FooLookup, 'Create branches named foo-')
232
self.addCleanup(directories.remove, 'foo:')
233
self.run_bzr('switch -b foo:branch2', working_dir='tree')
234
tree = WorkingTree.open('tree')
235
self.assertEndsWith(tree.branch.base, 'foo-branch2/')
237
def test_switch_with_post_switch_hook(self):
238
from bzrlib import branch as _mod_branch
240
_mod_branch.Branch.hooks.install_named_hook('post_switch',
242
self.make_branch_and_tree('branch')
243
self.run_bzr('branch branch branch2')
244
self.run_bzr('checkout branch checkout')
246
self.assertLength(0, calls)
247
out, err = self.run_bzr('switch ../branch2')
248
self.assertLength(1, calls)
250
def test_switch_lightweight_co_with_post_switch_hook(self):
251
from bzrlib import branch as _mod_branch
253
_mod_branch.Branch.hooks.install_named_hook('post_switch',
255
self.make_branch_and_tree('branch')
256
self.run_bzr('branch branch branch2')
257
self.run_bzr('checkout --lightweight branch checkout')
259
self.assertLength(0, calls)
260
out, err = self.run_bzr('switch ../branch2')
261
self.assertLength(1, calls)
263
def test_switch_lightweight_directory(self):
264
"""Test --directory option"""
266
# create a source branch
267
a_tree = self.make_branch_and_tree('a')
268
self.build_tree_contents([('a/a', 'initial\n')])
270
a_tree.commit(message='initial')
272
# clone and add a differing revision
273
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
274
self.build_tree_contents([('b/a', 'initial\nmore\n')])
275
b_tree.commit(message='more')
277
self.run_bzr('checkout --lightweight a checkout')
278
self.run_bzr('switch --directory checkout b')
279
self.assertFileEqual('initial\nmore\n', 'checkout/a')
282
class TestSwitchParentLocationBase(TestCaseWithTransport):
285
"""Set up a repository and branch ready for testing."""
286
super(TestSwitchParentLocationBase, self).setUp()
287
self.script_runner = script.ScriptRunner()
288
self.script_runner.run_script(self, '''
289
$ bzr init-repo --no-trees repo
292
shared repository: repo
293
$ bzr init repo/trunk
294
Created a repository branch...
295
Using shared repository: ...
298
def assertParent(self, expected_parent, branch):
299
"""Verify that the parent is not None and is set correctly."""
300
actual_parent = branch.get_parent()
301
self.assertIsSameRealPath(urlutils.local_path_to_url(expected_parent),
305
class TestSwitchParentLocation(TestSwitchParentLocationBase):
307
def _checkout_and_switch(self, option=''):
308
self.script_runner.run_script(self, '''
309
$ bzr checkout %(option)s repo/trunk checkout
311
$ bzr switch --create-branch switched
312
2>Tree is up to date at revision 0.
313
2>Switched to branch:...switched...
316
bound_branch = branch.Branch.open_containing('checkout')[0]
317
master_branch = branch.Branch.open_containing('repo/switched')[0]
318
return (bound_branch, master_branch)
320
def test_switch_parent_lightweight(self):
321
"""Lightweight checkout using bzr switch."""
322
bb, mb = self._checkout_and_switch(option='--lightweight')
323
self.assertParent('repo/trunk', bb)
324
self.assertParent('repo/trunk', mb)
326
def test_switch_parent_heavyweight(self):
327
"""Heavyweight checkout using bzr switch."""
328
bb, mb = self._checkout_and_switch()
329
self.assertParent('repo/trunk', bb)
330
self.assertParent('repo/trunk', mb)
333
class TestSwitchDoesntOpenMasterBranch(TestCaseWithTransport):
334
# See https://bugs.launchpad.net/bzr/+bug/812285
335
# "bzr switch --create-branch" can point the new branch's parent to the
336
# master branch, but it doesn't have to open it to do so.
338
def test_switch_create_doesnt_open_master_branch(self):
339
master = self.make_branch_and_tree('master')
341
# Note: not a lightweight checkout
342
checkout = master.branch.create_checkout('checkout')
344
def open_hook(branch):
345
# Just append the final directory of the branch
346
name = branch.base.rstrip('/').rsplit('/', 1)[1]
348
branch.Branch.hooks.install_named_hook('open', open_hook,
350
self.run_bzr('switch --create-branch -d checkout feature')
351
# We only open the master branch 1 time.
352
# This test should be cleaner to write, but see bug:
353
# https://bugs.launchpad.net/bzr/+bug/812295
354
self.assertEqual(1, opened.count('master'))