13
13
# You should have received a copy of the GNU General Public License
14
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Tests for the Branch facility that are not interface tests.
19
For interface tests see `tests/per_branch/*.py`.
19
For interface tests see tests/branch_implementations/*.py.
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
27
branch as _mod_branch,
36
branch as _mod_bzrbranch,
39
from ..bzr.fullhistory import (
43
from ..sixish import (
48
class TestErrors(tests.TestCase):
50
def test_unstackable_branch_format(self):
53
error = _mod_branch.UnstackableBranchFormat(format, url)
55
"The branch '/foo'(foo) is not a stackable format. "
56
"You will need to upgrade the branch to permit branch stacking.",
60
class TestDefaultFormat(tests.TestCase):
62
def test_default_format(self):
63
# update this if you change the default branch format
64
self.assertIsInstance(_mod_branch.format_registry.get_default(),
65
_mod_bzrbranch.BzrBranchFormat7)
67
def test_default_format_is_same_as_bzrdir_default(self):
68
# XXX: it might be nice if there was only one place the default was
69
# set, but at the moment that's not true -- mbp 20070814 --
70
# https://bugs.launchpad.net/bzr/+bug/132376
72
_mod_branch.format_registry.get_default(),
73
bzrdir.BzrDirFormat.get_default_format().get_branch_format())
25
from StringIO import StringIO
28
from bzrlib.branch import (BzrBranch5,
30
import bzrlib.bzrdir as bzrdir
31
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
33
from bzrlib.errors import (NotBranchError,
35
UnsupportedFormatError,
38
from bzrlib.tests import TestCase, TestCaseWithTransport
39
from bzrlib.transport import get_transport
41
class TestDefaultFormat(TestCase):
75
43
def test_get_set_default_format(self):
76
# set the format and then set it back again
77
old_format = _mod_branch.format_registry.get_default()
78
_mod_branch.format_registry.set_default(
44
old_format = bzrlib.branch.BranchFormat.get_default_format()
46
self.assertTrue(isinstance(old_format, bzrlib.branch.BzrBranchFormat5))
47
bzrlib.branch.BranchFormat.set_default_format(SampleBranchFormat())
81
49
# the default branch format is used by the meta dir format
82
50
# which is not the default bzrdir format at this point
83
dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
51
dir = BzrDirMetaFormat1().initialize('memory:/')
84
52
result = dir.create_branch()
85
53
self.assertEqual(result, 'A branch')
87
_mod_branch.format_registry.set_default(old_format)
88
self.assertEqual(old_format,
89
_mod_branch.format_registry.get_default())
92
class TestBranchFormat5(tests.TestCaseWithTransport):
55
bzrlib.branch.BranchFormat.set_default_format(old_format)
56
self.assertEqual(old_format, bzrlib.branch.BranchFormat.get_default_format())
59
class TestBranchFormat5(TestCaseWithTransport):
93
60
"""Tests specific to branch format 5"""
95
62
def test_branch_format_5_uses_lockdir(self):
96
63
url = self.get_url()
97
bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
98
bdir.create_repository()
99
branch = BzrBranchFormat5().initialize(bdir)
64
bzrdir = BzrDirMetaFormat1().initialize(url)
65
bzrdir.create_repository()
66
branch = bzrdir.create_branch()
100
67
t = self.get_transport()
101
68
self.log("branch instance is %r" % branch)
102
self.assertTrue(isinstance(branch, BzrBranch5))
69
self.assert_(isinstance(branch, BzrBranch5))
103
70
self.assertIsDirectory('.', t)
104
71
self.assertIsDirectory('.bzr/branch', t)
105
72
self.assertIsDirectory('.bzr/branch/lock', t)
106
73
branch.lock_write()
107
self.addCleanup(branch.unlock)
108
self.assertIsDirectory('.bzr/branch/lock/held', t)
110
def test_set_push_location(self):
111
conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
113
branch = self.make_branch('.', format='knit')
114
branch.set_push_location('foo')
115
local_path = urlutils.local_path_from_url(branch.base[:-1])
116
self.assertFileEqual(b"# comment\n"
118
b"push_location = foo\n"
119
b"push_location:policy = norecurse\n" % local_path.encode(
121
bedding.locations_config_path())
123
# TODO RBC 20051029 test getting a push location from a branch in a
124
# recursive section - that is, it appends the branch name.
127
class SampleBranchFormat(_mod_bzrbranch.BranchFormatMetadir):
75
self.assertIsDirectory('.bzr/branch/lock/held', t)
80
class TestBranchEscaping(TestCaseWithTransport):
81
"""Test a branch can be correctly stored and used on a vfat-like transport
83
Makes sure we have proper escaping of invalid characters, etc.
85
It'd be better to test all operations on the FakeVFATTransportDecorator,
86
but working trees go straight to the os not through the Transport layer.
87
Therefore we build some history first in the regular way and then
88
check it's safe to access for vfat.
95
super(TestBranchEscaping, self).setUp()
96
from bzrlib.repository import RepositoryFormatKnit1
97
bzrdir = BzrDirMetaFormat1().initialize(self.get_url())
98
repo = RepositoryFormatKnit1().initialize(bzrdir)
99
branch = bzrdir.create_branch()
100
wt = bzrdir.create_workingtree()
101
self.build_tree_contents([("foo", "contents of foo")])
102
# add file with id containing wierd characters
103
wt.add(['foo'], [self.FOO_ID])
104
wt.commit('this is my new commit', rev_id=self.REV_ID)
106
def test_branch_on_vfat(self):
107
from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
108
# now access over vfat; should be safe
109
transport = FakeVFATTransportDecorator('vfat+' + self.get_url())
110
bzrdir, junk = BzrDir.open_containing_from_transport(transport)
111
branch = bzrdir.open_branch()
112
revtree = branch.repository.revision_tree(self.REV_ID)
113
contents = revtree.get_file_text(self.FOO_ID)
114
self.assertEqual(contents, 'contents of foo')
117
class SampleBranchFormat(bzrlib.branch.BranchFormat):
128
118
"""A sample format
130
this format is initializable, unsupported to aid in testing the
120
this format is initializable, unsupported to aid in testing the
131
121
open and open_downlevel routines.
135
def get_format_string(cls):
124
def get_format_string(self):
136
125
"""See BzrBranchFormat.get_format_string()."""
137
return b"Sample branch format."
126
return "Sample branch format."
139
def initialize(self, a_controldir, name=None, repository=None,
140
append_revisions_only=None):
128
def initialize(self, a_bzrdir):
141
129
"""Format 4 branches cannot be created."""
142
t = a_controldir.get_branch_transport(self, name=name)
143
t.put_bytes('format', self.get_format_string())
130
t = a_bzrdir.get_branch_transport(self)
131
t.put('format', StringIO(self.get_format_string()))
144
132
return 'A branch'
146
134
def is_supported(self):
149
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
150
possible_transports=None):
137
def open(self, transport, _found=False):
151
138
return "opened branch."
154
# Demonstrating how lazy loading is often implemented:
155
# A constant string is created.
156
SampleSupportedBranchFormatString = b"Sample supported branch format."
158
# And the format class can then reference the constant to avoid skew.
161
class SampleSupportedBranchFormat(_mod_bzrbranch.BranchFormatMetadir):
162
"""A sample supported format."""
165
def get_format_string(cls):
166
"""See BzrBranchFormat.get_format_string()."""
167
return SampleSupportedBranchFormatString
169
def initialize(self, a_controldir, name=None, append_revisions_only=None):
170
t = a_controldir.get_branch_transport(self, name=name)
171
t.put_bytes('format', self.get_format_string())
174
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
175
possible_transports=None):
176
return "opened supported branch."
179
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
180
"""A sample format that is not usable in a metadir."""
182
def get_format_string(self):
183
# This format is not usable in a metadir.
186
def network_name(self):
187
# Network name always has to be provided.
190
def initialize(self, a_controldir, name=None):
191
raise NotImplementedError(self.initialize)
193
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
194
possible_transports=None):
195
raise NotImplementedError(self.open)
198
class TestBzrBranchFormat(tests.TestCaseWithTransport):
141
class TestBzrBranchFormat(TestCaseWithTransport):
199
142
"""Tests for the BzrBranchFormat facility."""
201
144
def test_find_format(self):
202
145
# is the right format object found for a branch?
203
146
# create a branch with a few known format objects.
204
# this is not quite the same as
147
# this is not quite the same as
205
148
self.build_tree(["foo/", "bar/"])
207
149
def check_format(format, url):
208
dir = format._matchingcontroldir.initialize(url)
150
dir = format._matchingbzrdir.initialize(url)
209
151
dir.create_repository()
210
152
format.initialize(dir)
211
found_format = _mod_bzrbranch.BranchFormatMetadir.find_format(dir)
212
self.assertIsInstance(found_format, format.__class__)
213
check_format(BzrBranchFormat5(), "bar")
215
def test_from_string(self):
216
self.assertIsInstance(
217
SampleBranchFormat.from_string(b"Sample branch format."),
219
self.assertRaises(AssertionError,
220
SampleBranchFormat.from_string, b"Different branch format.")
153
found_format = bzrlib.branch.BranchFormat.find_format(dir)
154
self.failUnless(isinstance(found_format, format.__class__))
155
check_format(bzrlib.branch.BzrBranchFormat5(), "bar")
222
157
def test_find_format_not_branch(self):
223
158
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
224
self.assertRaises(errors.NotBranchError,
225
_mod_bzrbranch.BranchFormatMetadir.find_format,
159
self.assertRaises(NotBranchError,
160
bzrlib.branch.BranchFormat.find_format,
228
163
def test_find_format_unknown_format(self):
229
164
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
230
165
SampleBranchFormat().initialize(dir)
231
self.assertRaises(errors.UnknownFormatError,
232
_mod_bzrbranch.BranchFormatMetadir.find_format,
166
self.assertRaises(UnknownFormatError,
167
bzrlib.branch.BranchFormat.find_format,
235
def test_find_format_with_features(self):
236
tree = self.make_branch_and_tree('.', format='2a')
237
tree.branch.update_feature_flags({b"name": b"optional"})
238
found_format = _mod_bzrbranch.BranchFormatMetadir.find_format(
240
self.assertIsInstance(found_format, _mod_bzrbranch.BranchFormatMetadir)
241
self.assertEqual(found_format.features.get(b"name"), b"optional")
242
tree.branch.update_feature_flags({b"name": None})
243
branch = _mod_branch.Branch.open('.')
244
self.assertEqual(branch._format.features, {})
247
class TestBranchFormatRegistry(tests.TestCase):
250
super(TestBranchFormatRegistry, self).setUp()
251
self.registry = _mod_branch.BranchFormatRegistry()
253
def test_default(self):
254
self.assertIs(None, self.registry.get_default())
255
format = SampleBranchFormat()
256
self.registry.set_default(format)
257
self.assertEqual(format, self.registry.get_default())
259
170
def test_register_unregister_format(self):
260
171
format = SampleBranchFormat()
261
self.registry.register(format)
262
self.assertEqual(format,
263
self.registry.get(b"Sample branch format."))
264
self.registry.remove(format)
265
self.assertRaises(KeyError, self.registry.get,
266
b"Sample branch format.")
268
def test_get_all(self):
269
format = SampleBranchFormat()
270
self.assertEqual([], self.registry._get_all())
271
self.registry.register(format)
272
self.assertEqual([format], self.registry._get_all())
274
def test_register_extra(self):
275
format = SampleExtraBranchFormat()
276
self.assertEqual([], self.registry._get_all())
277
self.registry.register_extra(format)
278
self.assertEqual([format], self.registry._get_all())
280
def test_register_extra_lazy(self):
281
self.assertEqual([], self.registry._get_all())
282
self.registry.register_extra_lazy("breezy.tests.test_branch",
283
"SampleExtraBranchFormat")
284
formats = self.registry._get_all()
285
self.assertEqual(1, len(formats))
286
self.assertIsInstance(formats[0], SampleExtraBranchFormat)
289
class TestBranch67(object):
290
"""Common tests for both branch 6 and 7 which are mostly the same."""
292
def get_format_name(self):
293
raise NotImplementedError(self.get_format_name)
295
def get_format_name_subtree(self):
296
raise NotImplementedError(self.get_format_name)
299
raise NotImplementedError(self.get_class)
301
def test_creation(self):
302
format = bzrdir.BzrDirMetaFormat1()
303
format.set_branch_format(_mod_bzrbranch.BzrBranchFormat6())
304
branch = self.make_branch('a', format=format)
305
self.assertIsInstance(branch, self.get_class())
306
branch = self.make_branch('b', format=self.get_format_name())
307
self.assertIsInstance(branch, self.get_class())
308
branch = _mod_branch.Branch.open('a')
309
self.assertIsInstance(branch, self.get_class())
311
def test_layout(self):
312
branch = self.make_branch('a', format=self.get_format_name())
313
self.assertPathExists('a/.bzr/branch/last-revision')
314
self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
315
self.assertPathDoesNotExist('a/.bzr/branch/references')
317
def test_config(self):
318
"""Ensure that all configuration data is stored in the branch"""
319
branch = self.make_branch('a', format=self.get_format_name())
320
branch.set_parent('http://example.com')
321
self.assertPathDoesNotExist('a/.bzr/branch/parent')
322
self.assertEqual('http://example.com', branch.get_parent())
323
branch.set_push_location('sftp://example.com')
324
conf = branch.get_config_stack()
325
self.assertEqual('sftp://example.com', conf.get('push_location'))
326
branch.set_bound_location('ftp://example.com')
327
self.assertPathDoesNotExist('a/.bzr/branch/bound')
328
self.assertEqual('ftp://example.com', branch.get_bound_location())
330
def do_checkout_test(self, lightweight):
331
tree = self.make_branch_and_tree('source',
332
format=self.get_format_name_subtree())
333
subtree = self.make_branch_and_tree('source/subtree',
334
format=self.get_format_name_subtree())
335
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
336
format=self.get_format_name_subtree())
337
self.build_tree(['source/subtree/file',
338
'source/subtree/subsubtree/file'])
339
subsubtree.add('file')
341
subtree.add_reference(subsubtree)
342
subtree.set_reference_info('subsubtree', subsubtree.branch.user_url)
343
tree.add_reference(subtree)
344
tree.set_reference_info('subtree', subtree.branch.user_url)
345
tree.commit('a revision')
346
subtree.commit('a subtree file')
347
subsubtree.commit('a subsubtree file')
348
tree.branch.create_checkout('target', lightweight=lightweight)
349
self.assertPathExists('target')
350
self.assertPathExists('target/subtree')
351
self.assertPathExists('target/subtree/file')
352
self.assertPathExists('target/subtree/subsubtree/file')
353
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
355
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
357
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
359
def test_checkout_with_references(self):
360
self.do_checkout_test(lightweight=False)
362
def test_light_checkout_with_references(self):
363
self.do_checkout_test(lightweight=True)
366
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
369
return _mod_bzrbranch.BzrBranch6
371
def get_format_name(self):
372
return "dirstate-tags"
374
def get_format_name_subtree(self):
375
return "dirstate-with-subtree"
377
def test_set_stacked_on_url_errors(self):
378
branch = self.make_branch('a', format=self.get_format_name())
379
self.assertRaises(_mod_branch.UnstackableBranchFormat,
380
branch.set_stacked_on_url, None)
382
def test_default_stacked_location(self):
383
branch = self.make_branch('a', format=self.get_format_name())
384
self.assertRaises(_mod_branch.UnstackableBranchFormat,
385
branch.get_stacked_on_url)
388
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
391
return _mod_bzrbranch.BzrBranch7
393
def get_format_name(self):
396
def get_format_name_subtree(self):
397
return "development-subtree"
399
def test_set_stacked_on_url_unstackable_repo(self):
400
repo = self.make_repository('a', format='dirstate-tags')
401
control = repo.controldir
402
branch = _mod_bzrbranch.BzrBranchFormat7().initialize(control)
403
target = self.make_branch('b')
404
self.assertRaises(errors.UnstackableRepositoryFormat,
405
branch.set_stacked_on_url, target.base)
407
def test_clone_stacked_on_unstackable_repo(self):
408
repo = self.make_repository('a', format='dirstate-tags')
409
control = repo.controldir
410
branch = _mod_bzrbranch.BzrBranchFormat7().initialize(control)
411
# Calling clone should not raise UnstackableRepositoryFormat.
412
cloned_bzrdir = control.clone('cloned')
414
def _test_default_stacked_location(self):
415
branch = self.make_branch('a', format=self.get_format_name())
416
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
418
def test_stack_and_unstack(self):
419
branch = self.make_branch('a', format=self.get_format_name())
420
target = self.make_branch_and_tree('b', format=self.get_format_name())
421
branch.set_stacked_on_url(target.branch.base)
422
self.assertEqual(target.branch.base, branch.get_stacked_on_url())
423
revid = target.commit('foo')
424
self.assertTrue(branch.repository.has_revision(revid))
425
branch.set_stacked_on_url(None)
426
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
427
self.assertFalse(branch.repository.has_revision(revid))
429
def test_open_opens_stacked_reference(self):
430
branch = self.make_branch('a', format=self.get_format_name())
431
target = self.make_branch_and_tree('b', format=self.get_format_name())
432
branch.set_stacked_on_url(target.branch.base)
433
branch = branch.controldir.open_branch()
434
revid = target.commit('foo')
435
self.assertTrue(branch.repository.has_revision(revid))
438
class BzrBranch8(tests.TestCaseWithTransport):
440
def make_branch(self, location, format=None):
442
format = controldir.format_registry.make_controldir('1.9')
443
format.set_branch_format(_mod_bzrbranch.BzrBranchFormat8())
444
return tests.TestCaseWithTransport.make_branch(
445
self, location, format=format)
447
def create_branch_with_reference(self):
448
branch = self.make_branch('branch')
449
branch._set_all_reference_info({'path': ('location', b'file-id')})
453
def instrument_branch(branch, gets):
454
old_get = branch._transport.get
456
def get(*args, **kwargs):
457
gets.append((args, kwargs))
458
return old_get(*args, **kwargs)
459
branch._transport.get = get
461
def test_reference_info_caching_read_locked(self):
463
branch = self.create_branch_with_reference()
465
self.addCleanup(branch.unlock)
466
self.instrument_branch(branch, gets)
467
branch.get_reference_info('path')
468
branch.get_reference_info('path')
469
self.assertEqual(1, len(gets))
471
def test_reference_info_caching_read_unlocked(self):
473
branch = self.create_branch_with_reference()
474
self.instrument_branch(branch, gets)
475
branch.get_reference_info('path')
476
branch.get_reference_info('path')
477
self.assertEqual(2, len(gets))
479
def test_reference_info_caching_write_locked(self):
481
branch = self.make_branch('branch')
483
self.instrument_branch(branch, gets)
484
self.addCleanup(branch.unlock)
485
branch._set_all_reference_info({'path2': ('location2', b'file-id')})
486
location, file_id = branch.get_reference_info('path2')
487
self.assertEqual(0, len(gets))
488
self.assertEqual(b'file-id', file_id)
489
self.assertEqual('location2', location)
491
def test_reference_info_caches_cleared(self):
492
branch = self.make_branch('branch')
493
with branch.lock_write():
494
branch.set_reference_info(b'file-id', 'location2', 'path2')
495
doppelganger = _mod_branch.Branch.open('branch')
496
doppelganger.set_reference_info(b'file-id', 'location3', 'path3')
497
self.assertEqual(('location3', 'path3'),
498
branch.get_reference_info(b'file-id'))
500
def _recordParentMapCalls(self, repo):
501
self._parent_map_calls = []
502
orig_get_parent_map = repo.revisions.get_parent_map
504
def get_parent_map(q):
506
self._parent_map_calls.extend([e[0] for e in q])
507
return orig_get_parent_map(q)
508
repo.revisions.get_parent_map = get_parent_map
511
class TestBranchReference(tests.TestCaseWithTransport):
173
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
175
format.initialize(dir)
176
# register a format for it.
177
bzrlib.branch.BranchFormat.register_format(format)
178
# which branch.Open will refuse (not supported)
179
self.assertRaises(UnsupportedFormatError, bzrlib.branch.Branch.open, self.get_url())
180
# but open_downlevel will work
181
self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
182
# unregister the format
183
bzrlib.branch.BranchFormat.unregister_format(format)
186
class TestBranchReference(TestCaseWithTransport):
512
187
"""Tests for the branch reference facility."""
514
189
def test_create_open_reference(self):
515
190
bzrdirformat = bzrdir.BzrDirMetaFormat1()
516
t = self.get_transport()
191
t = get_transport(self.get_url('.'))
518
193
dir = bzrdirformat.initialize(self.get_url('repo'))
519
194
dir.create_repository()
520
195
target_branch = dir.create_branch()
521
196
t.mkdir('branch')
522
197
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
523
made_branch = _mod_bzrbranch.BranchReferenceFormat().initialize(
524
branch_dir, target_branch=target_branch)
198
made_branch = bzrlib.branch.BranchReferenceFormat().initialize(branch_dir, target_branch)
525
199
self.assertEqual(made_branch.base, target_branch.base)
526
200
opened_branch = branch_dir.open_branch()
527
201
self.assertEqual(opened_branch.base, target_branch.base)
529
def test_get_reference(self):
530
"""For a BranchReference, get_reference should return the location."""
531
branch = self.make_branch('target')
532
checkout = branch.create_checkout('checkout', lightweight=True)
533
reference_url = branch.controldir.root_transport.abspath('') + '/'
534
# if the api for create_checkout changes to return different checkout types
535
# then this file read will fail.
536
self.assertFileEqual(reference_url.encode('utf-8'),
537
'checkout/.bzr/branch/location')
538
self.assertEqual(reference_url,
539
_mod_bzrbranch.BranchReferenceFormat().get_reference(checkout.controldir))
542
class TestHooks(tests.TestCaseWithTransport):
544
def test_constructor(self):
545
"""Check that creating a BranchHooks instance has the right defaults."""
546
hooks = _mod_branch.BranchHooks()
547
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
548
self.assertTrue("post_commit" in hooks,
549
"post_commit not in %s" % hooks)
550
self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
551
self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
552
self.assertTrue("post_uncommit" in hooks,
553
"post_uncommit not in %s" % hooks)
554
self.assertTrue("post_change_branch_tip" in hooks,
555
"post_change_branch_tip not in %s" % hooks)
556
self.assertTrue("post_branch_init" in hooks,
557
"post_branch_init not in %s" % hooks)
558
self.assertTrue("post_switch" in hooks,
559
"post_switch not in %s" % hooks)
561
def test_installed_hooks_are_BranchHooks(self):
562
"""The installed hooks object should be a BranchHooks."""
563
# the installed hooks are saved in self._preserved_hooks.
564
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
565
_mod_branch.BranchHooks)
567
def test_post_branch_init_hook(self):
569
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
571
self.assertLength(0, calls)
572
branch = self.make_branch('a')
573
self.assertLength(1, calls)
575
self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
576
self.assertTrue(hasattr(params, 'controldir'))
577
self.assertTrue(hasattr(params, 'branch'))
579
def test_post_branch_init_hook_repr(self):
581
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
582
lambda params: param_reprs.append(repr(params)), None)
583
branch = self.make_branch('a')
584
self.assertLength(1, param_reprs)
585
param_repr = param_reprs[0]
586
self.assertStartsWith(param_repr, '<BranchInitHookParams of ')
588
def test_post_switch_hook(self):
589
from .. import switch
591
_mod_branch.Branch.hooks.install_named_hook('post_switch',
593
tree = self.make_branch_and_tree('branch-1')
594
self.build_tree(['branch-1/file-1'])
597
to_branch = tree.controldir.sprout('branch-2').open_branch()
598
self.build_tree(['branch-1/file-2'])
600
tree.remove('file-1')
602
checkout = tree.branch.create_checkout('checkout')
603
self.assertLength(0, calls)
604
switch.switch(checkout.controldir, to_branch)
605
self.assertLength(1, calls)
607
self.assertIsInstance(params, _mod_branch.SwitchHookParams)
608
self.assertTrue(hasattr(params, 'to_branch'))
609
self.assertTrue(hasattr(params, 'revision_id'))
612
class TestBranchOptions(tests.TestCaseWithTransport):
615
super(TestBranchOptions, self).setUp()
616
self.branch = self.make_branch('.')
617
self.config_stack = self.branch.get_config_stack()
619
def check_append_revisions_only(self, expected_value, value=None):
620
"""Set append_revisions_only in config and check its interpretation."""
621
if value is not None:
622
self.config_stack.set('append_revisions_only', value)
623
self.assertEqual(expected_value,
624
self.branch.get_append_revisions_only())
626
def test_valid_append_revisions_only(self):
627
self.assertEqual(None,
628
self.config_stack.get('append_revisions_only'))
629
self.check_append_revisions_only(None)
630
self.check_append_revisions_only(False, 'False')
631
self.check_append_revisions_only(True, 'True')
632
# The following values will cause compatibility problems on projects
633
# using older bzr versions (<2.2) but are accepted
634
self.check_append_revisions_only(False, 'false')
635
self.check_append_revisions_only(True, 'true')
637
def test_invalid_append_revisions_only(self):
638
"""Ensure warning is noted on invalid settings"""
642
self.warnings.append(args[0] % args[1:])
643
self.overrideAttr(trace, 'warning', warning)
644
self.check_append_revisions_only(None, 'not-a-bool')
645
self.assertLength(1, self.warnings)
647
'Value "not-a-bool" is not valid for "append_revisions_only"',
650
def test_use_fresh_values(self):
651
copy = _mod_branch.Branch.open(self.branch.base)
654
copy.get_config_stack().set('foo', 'bar')
657
self.assertFalse(self.branch.is_locked())
658
# Since the branch is locked, the option value won't be saved on disk
659
# so trying to access the config of locked branch via another older
660
# non-locked branch object pointing to the same branch is not supported
661
self.assertEqual(None, self.branch.get_config_stack().get('foo'))
662
# Using a newly created branch object works as expected
663
fresh = _mod_branch.Branch.open(self.branch.base)
664
self.assertEqual('bar', fresh.get_config_stack().get('foo'))
666
def test_set_from_config_get_from_config_stack(self):
667
self.branch.lock_write()
668
self.addCleanup(self.branch.unlock)
669
self.branch.get_config().set_user_option('foo', 'bar')
670
result = self.branch.get_config_stack().get('foo')
671
# https://bugs.launchpad.net/bzr/+bug/948344
672
self.expectFailure('BranchStack uses cache after set_user_option',
673
self.assertEqual, 'bar', result)
675
def test_set_from_config_stack_get_from_config(self):
676
self.branch.lock_write()
677
self.addCleanup(self.branch.unlock)
678
self.branch.get_config_stack().set('foo', 'bar')
679
# Since the branch is locked, the option value won't be saved on disk
680
# so mixing get() and get_user_option() is broken by design.
681
self.assertEqual(None,
682
self.branch.get_config().get_user_option('foo'))
684
def test_set_delays_write_when_branch_is_locked(self):
685
self.branch.lock_write()
686
self.addCleanup(self.branch.unlock)
687
self.branch.get_config_stack().set('foo', 'bar')
688
copy = _mod_branch.Branch.open(self.branch.base)
689
result = copy.get_config_stack().get('foo')
690
# Accessing from a different branch object is like accessing from a
691
# different process: the option has not been saved yet and the new
692
# value cannot be seen.
693
self.assertIs(None, result)
696
class TestPullResult(tests.TestCase):
698
def test_report_changed(self):
699
r = _mod_branch.PullResult()
700
r.old_revid = b"old-revid"
702
r.new_revid = b"new-revid"
706
self.assertEqual("Now on revision 20.\n", f.getvalue())
708
def test_report_unchanged(self):
709
r = _mod_branch.PullResult()
710
r.old_revid = b"same-revid"
711
r.new_revid = b"same-revid"
714
self.assertEqual("No revisions or tags to pull.\n", f.getvalue())