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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Tests for the Branch facility that are not interface tests.
19
For interface tests see tests/branch_implementations/*.py.
19
For interface tests see `tests/per_branch/*.py`.
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
25
from StringIO import StringIO
25
from cStringIO import StringIO
27
27
from bzrlib import (
28
28
branch as _mod_branch,
34
from bzrlib.branch import (BzrBranch5,
36
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
38
from bzrlib.errors import (NotBranchError,
41
UnsupportedFormatError,
44
from bzrlib.tests import TestCase, TestCaseWithTransport
45
from bzrlib.transport import get_transport
47
class TestDefaultFormat(TestCase):
39
class TestDefaultFormat(tests.TestCase):
41
def test_default_format(self):
42
# update this if you change the default branch format
43
self.assertIsInstance(_mod_branch.format_registry.get_default(),
44
_mod_branch.BzrBranchFormat7)
46
def test_default_format_is_same_as_bzrdir_default(self):
47
# XXX: it might be nice if there was only one place the default was
48
# set, but at the moment that's not true -- mbp 20070814 --
49
# https://bugs.launchpad.net/bzr/+bug/132376
51
_mod_branch.format_registry.get_default(),
52
bzrdir.BzrDirFormat.get_default_format().get_branch_format())
49
54
def test_get_set_default_format(self):
50
old_format = bzrlib.branch.BranchFormat.get_default_format()
52
self.assertTrue(isinstance(old_format, bzrlib.branch.BzrBranchFormat5))
53
bzrlib.branch.BranchFormat.set_default_format(SampleBranchFormat())
55
# set the format and then set it back again
56
old_format = _mod_branch.format_registry.get_default()
57
_mod_branch.format_registry.set_default(SampleBranchFormat())
55
59
# the default branch format is used by the meta dir format
56
60
# which is not the default bzrdir format at this point
57
dir = BzrDirMetaFormat1().initialize('memory:///')
61
dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
58
62
result = dir.create_branch()
59
63
self.assertEqual(result, 'A branch')
61
bzrlib.branch.BranchFormat.set_default_format(old_format)
62
self.assertEqual(old_format, bzrlib.branch.BranchFormat.get_default_format())
65
class TestBranchFormat5(TestCaseWithTransport):
65
_mod_branch.format_registry.set_default(old_format)
66
self.assertEqual(old_format,
67
_mod_branch.format_registry.get_default())
70
class TestBranchFormat5(tests.TestCaseWithTransport):
66
71
"""Tests specific to branch format 5"""
68
73
def test_branch_format_5_uses_lockdir(self):
69
74
url = self.get_url()
70
bzrdir = BzrDirMetaFormat1().initialize(url)
71
bzrdir.create_repository()
72
branch = bzrdir.create_branch()
75
bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
76
bdir.create_repository()
77
branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
73
78
t = self.get_transport()
74
79
self.log("branch instance is %r" % branch)
75
self.assert_(isinstance(branch, BzrBranch5))
80
self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
76
81
self.assertIsDirectory('.', t)
77
82
self.assertIsDirectory('.bzr/branch', t)
78
83
self.assertIsDirectory('.bzr/branch/lock', t)
79
84
branch.lock_write()
81
self.assertIsDirectory('.bzr/branch/lock/held', t)
85
self.addCleanup(branch.unlock)
86
self.assertIsDirectory('.bzr/branch/lock/held', t)
85
88
def test_set_push_location(self):
86
from bzrlib.config import (locations_config_filename,
87
ensure_config_dir_exists)
88
ensure_config_dir_exists()
89
fn = locations_config_filename()
89
conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
90
91
branch = self.make_branch('.', format='knit')
91
92
branch.set_push_location('foo')
92
93
local_path = urlutils.local_path_from_url(branch.base[:-1])
93
self.assertFileEqual("[%s]\n"
94
self.assertFileEqual("# comment\n"
94
96
"push_location = foo\n"
95
"push_location:policy = norecurse" % local_path,
97
"push_location:policy = norecurse\n" % local_path,
98
config.locations_config_filename())
98
100
# TODO RBC 20051029 test getting a push location from a branch in a
99
101
# recursive section - that is, it appends the branch name.
102
class SampleBranchFormat(bzrlib.branch.BranchFormat):
104
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
103
105
"""A sample format
105
this format is initializable, unsupported to aid in testing the
107
this format is initializable, unsupported to aid in testing the
106
108
open and open_downlevel routines.
109
def get_format_string(self):
112
def get_format_string(cls):
110
113
"""See BzrBranchFormat.get_format_string()."""
111
114
return "Sample branch format."
113
def initialize(self, a_bzrdir):
116
def initialize(self, a_bzrdir, name=None, repository=None,
117
append_revisions_only=None):
114
118
"""Format 4 branches cannot be created."""
115
t = a_bzrdir.get_branch_transport(self)
119
t = a_bzrdir.get_branch_transport(self, name=name)
116
120
t.put_bytes('format', self.get_format_string())
117
121
return 'A branch'
119
123
def is_supported(self):
122
def open(self, transport, _found=False):
126
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
127
possible_transports=None):
123
128
return "opened branch."
126
class TestBzrBranchFormat(TestCaseWithTransport):
131
# Demonstrating how lazy loading is often implemented:
132
# A constant string is created.
133
SampleSupportedBranchFormatString = "Sample supported branch format."
135
# And the format class can then reference the constant to avoid skew.
136
class SampleSupportedBranchFormat(_mod_branch.BranchFormatMetadir):
137
"""A sample supported format."""
140
def get_format_string(cls):
141
"""See BzrBranchFormat.get_format_string()."""
142
return SampleSupportedBranchFormatString
144
def initialize(self, a_bzrdir, name=None, append_revisions_only=None):
145
t = a_bzrdir.get_branch_transport(self, name=name)
146
t.put_bytes('format', self.get_format_string())
149
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
150
possible_transports=None):
151
return "opened supported branch."
154
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
155
"""A sample format that is not usable in a metadir."""
157
def get_format_string(self):
158
# This format is not usable in a metadir.
161
def network_name(self):
162
# Network name always has to be provided.
165
def initialize(self, a_bzrdir, name=None):
166
raise NotImplementedError(self.initialize)
168
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
169
possible_transports=None):
170
raise NotImplementedError(self.open)
173
class TestBzrBranchFormat(tests.TestCaseWithTransport):
127
174
"""Tests for the BzrBranchFormat facility."""
129
176
def test_find_format(self):
130
177
# is the right format object found for a branch?
131
178
# create a branch with a few known format objects.
132
# this is not quite the same as
179
# this is not quite the same as
133
180
self.build_tree(["foo/", "bar/"])
134
181
def check_format(format, url):
135
182
dir = format._matchingbzrdir.initialize(url)
136
183
dir.create_repository()
137
184
format.initialize(dir)
138
found_format = bzrlib.branch.BranchFormat.find_format(dir)
139
self.failUnless(isinstance(found_format, format.__class__))
140
check_format(bzrlib.branch.BzrBranchFormat5(), "bar")
185
found_format = _mod_branch.BranchFormatMetadir.find_format(dir)
186
self.assertIsInstance(found_format, format.__class__)
187
check_format(_mod_branch.BzrBranchFormat5(), "bar")
189
def test_find_format_factory(self):
190
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
191
SampleSupportedBranchFormat().initialize(dir)
192
factory = _mod_branch.MetaDirBranchFormatFactory(
193
SampleSupportedBranchFormatString,
194
"bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
195
_mod_branch.format_registry.register(factory)
196
self.addCleanup(_mod_branch.format_registry.remove, factory)
197
b = _mod_branch.Branch.open(self.get_url())
198
self.assertEqual(b, "opened supported branch.")
200
def test_from_string(self):
201
self.assertIsInstance(
202
SampleBranchFormat.from_string("Sample branch format."),
204
self.assertRaises(ValueError,
205
SampleBranchFormat.from_string, "Different branch format.")
142
207
def test_find_format_not_branch(self):
143
208
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
144
self.assertRaises(NotBranchError,
145
bzrlib.branch.BranchFormat.find_format,
209
self.assertRaises(errors.NotBranchError,
210
_mod_branch.BranchFormatMetadir.find_format,
148
213
def test_find_format_unknown_format(self):
149
214
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
150
215
SampleBranchFormat().initialize(dir)
151
self.assertRaises(UnknownFormatError,
152
bzrlib.branch.BranchFormat.find_format,
216
self.assertRaises(errors.UnknownFormatError,
217
_mod_branch.BranchFormatMetadir.find_format,
155
220
def test_register_unregister_format(self):
221
# Test the deprecated format registration functions
156
222
format = SampleBranchFormat()
157
223
# make a control dir
158
224
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
160
226
format.initialize(dir)
161
227
# register a format for it.
162
bzrlib.branch.BranchFormat.register_format(format)
228
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
229
_mod_branch.BranchFormat.register_format, format)
163
230
# which branch.Open will refuse (not supported)
164
self.assertRaises(UnsupportedFormatError, bzrlib.branch.Branch.open, self.get_url())
231
self.assertRaises(errors.UnsupportedFormatError,
232
_mod_branch.Branch.open, self.get_url())
165
233
self.make_branch_and_tree('foo')
166
234
# but open_downlevel will work
167
self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
237
bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
168
238
# unregister the format
169
bzrlib.branch.BranchFormat.unregister_format(format)
239
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
240
_mod_branch.BranchFormat.unregister_format, format)
170
241
self.make_branch_and_tree('bar')
172
def test_checkout_format(self):
173
branch = self.make_repository('repository', shared=True)
174
branch = self.make_branch('repository/branch',
176
tree = branch.create_checkout('checkout')
177
self.assertIs(tree.branch.__class__, _mod_branch.BzrBranch5)
180
class TestBranch6(TestCaseWithTransport):
244
class TestBranchFormatRegistry(tests.TestCase):
247
super(TestBranchFormatRegistry, self).setUp()
248
self.registry = _mod_branch.BranchFormatRegistry()
250
def test_default(self):
251
self.assertIs(None, self.registry.get_default())
252
format = SampleBranchFormat()
253
self.registry.set_default(format)
254
self.assertEquals(format, self.registry.get_default())
256
def test_register_unregister_format(self):
257
format = SampleBranchFormat()
258
self.registry.register(format)
259
self.assertEquals(format,
260
self.registry.get("Sample branch format."))
261
self.registry.remove(format)
262
self.assertRaises(KeyError, self.registry.get,
263
"Sample branch format.")
265
def test_get_all(self):
266
format = SampleBranchFormat()
267
self.assertEquals([], self.registry._get_all())
268
self.registry.register(format)
269
self.assertEquals([format], self.registry._get_all())
271
def test_register_extra(self):
272
format = SampleExtraBranchFormat()
273
self.assertEquals([], self.registry._get_all())
274
self.registry.register_extra(format)
275
self.assertEquals([format], self.registry._get_all())
277
def test_register_extra_lazy(self):
278
self.assertEquals([], self.registry._get_all())
279
self.registry.register_extra_lazy("bzrlib.tests.test_branch",
280
"SampleExtraBranchFormat")
281
formats = self.registry._get_all()
282
self.assertEquals(1, len(formats))
283
self.assertIsInstance(formats[0], SampleExtraBranchFormat)
286
#Used by TestMetaDirBranchFormatFactory
287
FakeLazyFormat = None
290
class TestMetaDirBranchFormatFactory(tests.TestCase):
292
def test_get_format_string_does_not_load(self):
293
"""Formats have a static format string."""
294
factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
295
self.assertEqual("yo", factory.get_format_string())
297
def test_call_loads(self):
298
# __call__ is used by the network_format_registry interface to get a
300
global FakeLazyFormat
302
factory = _mod_branch.MetaDirBranchFormatFactory(None,
303
"bzrlib.tests.test_branch", "FakeLazyFormat")
304
self.assertRaises(AttributeError, factory)
306
def test_call_returns_call_of_referenced_object(self):
307
global FakeLazyFormat
308
FakeLazyFormat = lambda:'called'
309
factory = _mod_branch.MetaDirBranchFormatFactory(None,
310
"bzrlib.tests.test_branch", "FakeLazyFormat")
311
self.assertEqual('called', factory())
314
class TestBranch67(object):
315
"""Common tests for both branch 6 and 7 which are mostly the same."""
317
def get_format_name(self):
318
raise NotImplementedError(self.get_format_name)
320
def get_format_name_subtree(self):
321
raise NotImplementedError(self.get_format_name)
324
raise NotImplementedError(self.get_class)
182
326
def test_creation(self):
183
format = BzrDirMetaFormat1()
327
format = bzrdir.BzrDirMetaFormat1()
184
328
format.set_branch_format(_mod_branch.BzrBranchFormat6())
185
329
branch = self.make_branch('a', format=format)
186
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
187
branch = self.make_branch('b', format='experimental-branch6')
188
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
330
self.assertIsInstance(branch, self.get_class())
331
branch = self.make_branch('b', format=self.get_format_name())
332
self.assertIsInstance(branch, self.get_class())
189
333
branch = _mod_branch.Branch.open('a')
190
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
334
self.assertIsInstance(branch, self.get_class())
192
336
def test_layout(self):
193
branch = self.make_branch('a', format='experimental-branch6')
194
self.failUnlessExists('a/.bzr/branch/last-revision')
195
self.failIfExists('a/.bzr/branch/revision-history')
337
branch = self.make_branch('a', format=self.get_format_name())
338
self.assertPathExists('a/.bzr/branch/last-revision')
339
self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
340
self.assertPathDoesNotExist('a/.bzr/branch/references')
197
342
def test_config(self):
198
343
"""Ensure that all configuration data is stored in the branch"""
199
branch = self.make_branch('a', format='experimental-branch6')
200
branch.set_parent('http://bazaar-vcs.org')
201
self.failIfExists('a/.bzr/branch/parent')
202
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
203
branch.set_push_location('sftp://bazaar-vcs.org')
344
branch = self.make_branch('a', format=self.get_format_name())
345
branch.set_parent('http://example.com')
346
self.assertPathDoesNotExist('a/.bzr/branch/parent')
347
self.assertEqual('http://example.com', branch.get_parent())
348
branch.set_push_location('sftp://example.com')
204
349
config = branch.get_config()._get_branch_data_config()
205
self.assertEqual('sftp://bazaar-vcs.org',
350
self.assertEqual('sftp://example.com',
206
351
config.get_user_option('push_location'))
207
branch.set_bound_location('ftp://bazaar-vcs.org')
208
self.failIfExists('a/.bzr/branch/bound')
209
self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
352
branch.set_bound_location('ftp://example.com')
353
self.assertPathDoesNotExist('a/.bzr/branch/bound')
354
self.assertEqual('ftp://example.com', branch.get_bound_location())
211
356
def test_set_revision_history(self):
212
tree = self.make_branch_and_memory_tree('.',
213
format='experimental-branch6')
217
tree.commit('foo', rev_id='foo')
218
tree.commit('bar', rev_id='bar')
219
tree.branch.set_revision_history(['foo', 'bar'])
220
tree.branch.set_revision_history(['foo'])
221
self.assertRaises(errors.NotLefthandHistory,
222
tree.branch.set_revision_history, ['bar'])
226
def test_append_revision(self):
227
tree = self.make_branch_and_tree('branch1',
228
format='experimental-branch6')
232
tree.commit('foo', rev_id='foo')
233
tree.commit('bar', rev_id='bar')
234
tree.commit('baz', rev_id='baz')
235
tree.set_last_revision('bar')
236
tree.branch.set_last_revision_info(2, 'bar')
237
tree.commit('qux', rev_id='qux')
238
tree.add_parent_tree_id('baz')
239
tree.commit('qux', rev_id='quxx')
240
tree.branch.set_last_revision_info(0, 'null:')
241
self.assertRaises(errors.NotLeftParentDescendant,
242
tree.branch.append_revision, 'bar')
243
tree.branch.append_revision('foo')
244
self.assertRaises(errors.NotLeftParentDescendant,
245
tree.branch.append_revision, 'baz')
246
tree.branch.append_revision('bar')
247
tree.branch.append_revision('baz')
248
self.assertRaises(errors.NotLeftParentDescendant,
249
tree.branch.append_revision, 'quxx')
254
class TestBranchReference(TestCaseWithTransport):
357
builder = self.make_branch_builder('.', format=self.get_format_name())
358
builder.build_snapshot('foo', None,
359
[('add', ('', None, 'directory', None))],
361
builder.build_snapshot('bar', None, [], message='bar')
362
branch = builder.get_branch()
364
self.addCleanup(branch.unlock)
365
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
366
branch.set_revision_history, ['foo', 'bar'])
367
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
368
branch.set_revision_history, ['foo'])
369
self.assertRaises(errors.NotLefthandHistory,
370
self.applyDeprecated, symbol_versioning.deprecated_in((2, 4, 0)),
371
branch.set_revision_history, ['bar'])
373
def do_checkout_test(self, lightweight=False):
374
tree = self.make_branch_and_tree('source',
375
format=self.get_format_name_subtree())
376
subtree = self.make_branch_and_tree('source/subtree',
377
format=self.get_format_name_subtree())
378
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
379
format=self.get_format_name_subtree())
380
self.build_tree(['source/subtree/file',
381
'source/subtree/subsubtree/file'])
382
subsubtree.add('file')
384
subtree.add_reference(subsubtree)
385
tree.add_reference(subtree)
386
tree.commit('a revision')
387
subtree.commit('a subtree file')
388
subsubtree.commit('a subsubtree file')
389
tree.branch.create_checkout('target', lightweight=lightweight)
390
self.assertPathExists('target')
391
self.assertPathExists('target/subtree')
392
self.assertPathExists('target/subtree/file')
393
self.assertPathExists('target/subtree/subsubtree/file')
394
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
396
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
398
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
400
def test_checkout_with_references(self):
401
self.do_checkout_test()
403
def test_light_checkout_with_references(self):
404
self.do_checkout_test(lightweight=True)
406
def test_set_push(self):
407
branch = self.make_branch('source', format=self.get_format_name())
408
branch.get_config().set_user_option('push_location', 'old',
409
store=config.STORE_LOCATION)
412
warnings.append(args[0] % args[1:])
413
_warning = trace.warning
414
trace.warning = warning
416
branch.set_push_location('new')
418
trace.warning = _warning
419
self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
423
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
426
return _mod_branch.BzrBranch6
428
def get_format_name(self):
429
return "dirstate-tags"
431
def get_format_name_subtree(self):
432
return "dirstate-with-subtree"
434
def test_set_stacked_on_url_errors(self):
435
branch = self.make_branch('a', format=self.get_format_name())
436
self.assertRaises(errors.UnstackableBranchFormat,
437
branch.set_stacked_on_url, None)
439
def test_default_stacked_location(self):
440
branch = self.make_branch('a', format=self.get_format_name())
441
self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
444
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
447
return _mod_branch.BzrBranch7
449
def get_format_name(self):
452
def get_format_name_subtree(self):
453
return "development-subtree"
455
def test_set_stacked_on_url_unstackable_repo(self):
456
repo = self.make_repository('a', format='dirstate-tags')
457
control = repo.bzrdir
458
branch = _mod_branch.BzrBranchFormat7().initialize(control)
459
target = self.make_branch('b')
460
self.assertRaises(errors.UnstackableRepositoryFormat,
461
branch.set_stacked_on_url, target.base)
463
def test_clone_stacked_on_unstackable_repo(self):
464
repo = self.make_repository('a', format='dirstate-tags')
465
control = repo.bzrdir
466
branch = _mod_branch.BzrBranchFormat7().initialize(control)
467
# Calling clone should not raise UnstackableRepositoryFormat.
468
cloned_bzrdir = control.clone('cloned')
470
def _test_default_stacked_location(self):
471
branch = self.make_branch('a', format=self.get_format_name())
472
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
474
def test_stack_and_unstack(self):
475
branch = self.make_branch('a', format=self.get_format_name())
476
target = self.make_branch_and_tree('b', format=self.get_format_name())
477
branch.set_stacked_on_url(target.branch.base)
478
self.assertEqual(target.branch.base, branch.get_stacked_on_url())
479
revid = target.commit('foo')
480
self.assertTrue(branch.repository.has_revision(revid))
481
branch.set_stacked_on_url(None)
482
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
483
self.assertFalse(branch.repository.has_revision(revid))
485
def test_open_opens_stacked_reference(self):
486
branch = self.make_branch('a', format=self.get_format_name())
487
target = self.make_branch_and_tree('b', format=self.get_format_name())
488
branch.set_stacked_on_url(target.branch.base)
489
branch = branch.bzrdir.open_branch()
490
revid = target.commit('foo')
491
self.assertTrue(branch.repository.has_revision(revid))
494
class BzrBranch8(tests.TestCaseWithTransport):
496
def make_branch(self, location, format=None):
498
format = bzrdir.format_registry.make_bzrdir('1.9')
499
format.set_branch_format(_mod_branch.BzrBranchFormat8())
500
return tests.TestCaseWithTransport.make_branch(
501
self, location, format=format)
503
def create_branch_with_reference(self):
504
branch = self.make_branch('branch')
505
branch._set_all_reference_info({'file-id': ('path', 'location')})
509
def instrument_branch(branch, gets):
510
old_get = branch._transport.get
511
def get(*args, **kwargs):
512
gets.append((args, kwargs))
513
return old_get(*args, **kwargs)
514
branch._transport.get = get
516
def test_reference_info_caching_read_locked(self):
518
branch = self.create_branch_with_reference()
520
self.addCleanup(branch.unlock)
521
self.instrument_branch(branch, gets)
522
branch.get_reference_info('file-id')
523
branch.get_reference_info('file-id')
524
self.assertEqual(1, len(gets))
526
def test_reference_info_caching_read_unlocked(self):
528
branch = self.create_branch_with_reference()
529
self.instrument_branch(branch, gets)
530
branch.get_reference_info('file-id')
531
branch.get_reference_info('file-id')
532
self.assertEqual(2, len(gets))
534
def test_reference_info_caching_write_locked(self):
536
branch = self.make_branch('branch')
538
self.instrument_branch(branch, gets)
539
self.addCleanup(branch.unlock)
540
branch._set_all_reference_info({'file-id': ('path2', 'location2')})
541
path, location = branch.get_reference_info('file-id')
542
self.assertEqual(0, len(gets))
543
self.assertEqual('path2', path)
544
self.assertEqual('location2', location)
546
def test_reference_info_caches_cleared(self):
547
branch = self.make_branch('branch')
549
branch.set_reference_info('file-id', 'path2', 'location2')
551
doppelganger = _mod_branch.Branch.open('branch')
552
doppelganger.set_reference_info('file-id', 'path3', 'location3')
553
self.assertEqual(('path3', 'location3'),
554
branch.get_reference_info('file-id'))
556
def _recordParentMapCalls(self, repo):
557
self._parent_map_calls = []
558
orig_get_parent_map = repo.revisions.get_parent_map
559
def get_parent_map(q):
561
self._parent_map_calls.extend([e[0] for e in q])
562
return orig_get_parent_map(q)
563
repo.revisions.get_parent_map = get_parent_map
566
class TestBranchReference(tests.TestCaseWithTransport):
255
567
"""Tests for the branch reference facility."""
257
569
def test_create_open_reference(self):
258
570
bzrdirformat = bzrdir.BzrDirMetaFormat1()
259
t = get_transport(self.get_url('.'))
571
t = self.get_transport()
261
573
dir = bzrdirformat.initialize(self.get_url('repo'))
262
574
dir.create_repository()
263
575
target_branch = dir.create_branch()
264
576
t.mkdir('branch')
265
577
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
266
made_branch = bzrlib.branch.BranchReferenceFormat().initialize(branch_dir, target_branch)
578
made_branch = _mod_branch.BranchReferenceFormat().initialize(
579
branch_dir, target_branch=target_branch)
267
580
self.assertEqual(made_branch.base, target_branch.base)
268
581
opened_branch = branch_dir.open_branch()
269
582
self.assertEqual(opened_branch.base, target_branch.base)
272
class TestHooks(TestCase):
584
def test_get_reference(self):
585
"""For a BranchReference, get_reference should reutrn the location."""
586
branch = self.make_branch('target')
587
checkout = branch.create_checkout('checkout', lightweight=True)
588
reference_url = branch.bzrdir.root_transport.abspath('') + '/'
589
# if the api for create_checkout changes to return different checkout types
590
# then this file read will fail.
591
self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
592
self.assertEqual(reference_url,
593
_mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
596
class TestHooks(tests.TestCaseWithTransport):
274
598
def test_constructor(self):
275
599
"""Check that creating a BranchHooks instance has the right defaults."""
276
hooks = bzrlib.branch.BranchHooks()
600
hooks = _mod_branch.BranchHooks()
277
601
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
278
602
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
279
603
self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
604
self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
280
605
self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
281
self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
606
self.assertTrue("post_uncommit" in hooks,
607
"post_uncommit not in %s" % hooks)
608
self.assertTrue("post_change_branch_tip" in hooks,
609
"post_change_branch_tip not in %s" % hooks)
610
self.assertTrue("post_branch_init" in hooks,
611
"post_branch_init not in %s" % hooks)
612
self.assertTrue("post_switch" in hooks,
613
"post_switch not in %s" % hooks)
283
615
def test_installed_hooks_are_BranchHooks(self):
284
616
"""The installed hooks object should be a BranchHooks."""
285
617
# the installed hooks are saved in self._preserved_hooks.
286
self.assertIsInstance(self._preserved_hooks, bzrlib.branch.BranchHooks)
288
def test_install_hook_raises_unknown_hook(self):
289
"""install_hook should raise UnknownHook if a hook is unknown."""
290
hooks = bzrlib.branch.BranchHooks()
291
self.assertRaises(UnknownHook, hooks.install_hook, 'silly', None)
293
def test_install_hook_appends_known_hook(self):
294
"""install_hook should append the callable for known hooks."""
295
hooks = bzrlib.branch.BranchHooks()
296
hooks.install_hook('set_rh', None)
297
self.assertEqual(hooks['set_rh'], [None])
618
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
619
_mod_branch.BranchHooks)
621
def test_post_branch_init_hook(self):
623
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
625
self.assertLength(0, calls)
626
branch = self.make_branch('a')
627
self.assertLength(1, calls)
629
self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
630
self.assertTrue(hasattr(params, 'bzrdir'))
631
self.assertTrue(hasattr(params, 'branch'))
633
def test_post_branch_init_hook_repr(self):
635
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
636
lambda params: param_reprs.append(repr(params)), None)
637
branch = self.make_branch('a')
638
self.assertLength(1, param_reprs)
639
param_repr = param_reprs[0]
640
self.assertStartsWith(param_repr, '<BranchInitHookParams of ')
642
def test_post_switch_hook(self):
643
from bzrlib import switch
645
_mod_branch.Branch.hooks.install_named_hook('post_switch',
647
tree = self.make_branch_and_tree('branch-1')
648
self.build_tree(['branch-1/file-1'])
651
to_branch = tree.bzrdir.sprout('branch-2').open_branch()
652
self.build_tree(['branch-1/file-2'])
654
tree.remove('file-1')
656
checkout = tree.branch.create_checkout('checkout')
657
self.assertLength(0, calls)
658
switch.switch(checkout.bzrdir, to_branch)
659
self.assertLength(1, calls)
661
self.assertIsInstance(params, _mod_branch.SwitchHookParams)
662
self.assertTrue(hasattr(params, 'to_branch'))
663
self.assertTrue(hasattr(params, 'revision_id'))
666
class TestBranchOptions(tests.TestCaseWithTransport):
669
super(TestBranchOptions, self).setUp()
670
self.branch = self.make_branch('.')
671
self.config_stack = self.branch.get_config_stack()
673
def check_append_revisions_only(self, expected_value, value=None):
674
"""Set append_revisions_only in config and check its interpretation."""
675
if value is not None:
676
self.config_stack.set('append_revisions_only', value)
677
self.assertEqual(expected_value,
678
self.branch.get_append_revisions_only())
680
def test_valid_append_revisions_only(self):
681
self.assertEquals(None,
682
self.config_stack.get('append_revisions_only'))
683
self.check_append_revisions_only(None)
684
self.check_append_revisions_only(False, 'False')
685
self.check_append_revisions_only(True, 'True')
686
# The following values will cause compatibility problems on projects
687
# using older bzr versions (<2.2) but are accepted
688
self.check_append_revisions_only(False, 'false')
689
self.check_append_revisions_only(True, 'true')
691
def test_invalid_append_revisions_only(self):
692
"""Ensure warning is noted on invalid settings"""
695
self.warnings.append(args[0] % args[1:])
696
self.overrideAttr(trace, 'warning', warning)
697
self.check_append_revisions_only(None, 'not-a-bool')
698
self.assertLength(1, self.warnings)
700
'Value "not-a-bool" is not valid for "append_revisions_only"',
704
class TestPullResult(tests.TestCase):
706
def test_pull_result_to_int(self):
707
# to support old code, the pull result can be used as an int
708
r = _mod_branch.PullResult()
711
# this usage of results is not recommended for new code (because it
712
# doesn't describe very well what happened), but for api stability
713
# it's still supported
714
self.assertEqual(self.applyDeprecated(
715
symbol_versioning.deprecated_in((2, 3, 0)),
719
def test_report_changed(self):
720
r = _mod_branch.PullResult()
721
r.old_revid = "old-revid"
723
r.new_revid = "new-revid"
727
self.assertEqual("Now on revision 20.\n", f.getvalue())
728
self.assertEqual("Now on revision 20.\n", f.getvalue())
730
def test_report_unchanged(self):
731
r = _mod_branch.PullResult()
732
r.old_revid = "same-revid"
733
r.new_revid = "same-revid"
736
self.assertEqual("No revisions or tags to pull.\n", f.getvalue())