~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
"""Tests for the Branch facility that are not interface  tests.
18
18
 
19
 
For interface tests see tests/per_branch/*.py.
 
19
For interface tests see `tests/per_branch/*.py`.
20
20
 
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
23
23
"""
24
24
 
25
 
from StringIO import StringIO
 
25
from cStringIO import StringIO
26
26
 
27
27
from bzrlib import (
28
28
    branch as _mod_branch,
29
29
    bzrdir,
30
30
    config,
31
31
    errors,
 
32
    symbol_versioning,
 
33
    tests,
32
34
    trace,
33
35
    urlutils,
34
36
    )
35
 
from bzrlib.branch import (
36
 
    Branch,
37
 
    BranchHooks,
38
 
    BranchFormat,
39
 
    BranchReferenceFormat,
40
 
    BzrBranch5,
41
 
    BzrBranchFormat5,
42
 
    BzrBranchFormat6,
43
 
    BzrBranchFormat7,
44
 
    PullResult,
45
 
    _run_with_write_locked_target,
46
 
    )
47
 
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
48
 
                           BzrDir, BzrDirFormat)
49
 
from bzrlib.errors import (NotBranchError,
50
 
                           UnknownFormatError,
51
 
                           UnknownHook,
52
 
                           UnsupportedFormatError,
53
 
                           )
54
 
 
55
 
from bzrlib.tests import TestCase, TestCaseWithTransport
56
 
from bzrlib.transport import get_transport
57
 
 
58
 
 
59
 
class TestDefaultFormat(TestCase):
 
37
 
 
38
 
 
39
class TestDefaultFormat(tests.TestCase):
60
40
 
61
41
    def test_default_format(self):
62
42
        # update this if you change the default branch format
63
 
        self.assertIsInstance(BranchFormat.get_default_format(),
64
 
                BzrBranchFormat7)
 
43
        self.assertIsInstance(_mod_branch.format_registry.get_default(),
 
44
                _mod_branch.BzrBranchFormat7)
65
45
 
66
46
    def test_default_format_is_same_as_bzrdir_default(self):
67
47
        # XXX: it might be nice if there was only one place the default was
68
48
        # set, but at the moment that's not true -- mbp 20070814 --
69
49
        # https://bugs.launchpad.net/bzr/+bug/132376
70
 
        self.assertEqual(BranchFormat.get_default_format(),
71
 
                BzrDirFormat.get_default_format().get_branch_format())
 
50
        self.assertEqual(
 
51
            _mod_branch.format_registry.get_default(),
 
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
72
53
 
73
54
    def test_get_set_default_format(self):
74
55
        # set the format and then set it back again
75
 
        old_format = BranchFormat.get_default_format()
76
 
        BranchFormat.set_default_format(SampleBranchFormat())
 
56
        old_format = _mod_branch.format_registry.get_default()
 
57
        _mod_branch.format_registry.set_default(SampleBranchFormat())
77
58
        try:
78
59
            # the default branch format is used by the meta dir format
79
60
            # which is not the default bzrdir format at this point
80
 
            dir = BzrDirMetaFormat1().initialize('memory:///')
 
61
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
81
62
            result = dir.create_branch()
82
63
            self.assertEqual(result, 'A branch')
83
64
        finally:
84
 
            BranchFormat.set_default_format(old_format)
85
 
        self.assertEqual(old_format, BranchFormat.get_default_format())
86
 
 
87
 
 
88
 
class TestBranchFormat5(TestCaseWithTransport):
 
65
            _mod_branch.format_registry.set_default(old_format)
 
66
        self.assertEqual(old_format,
 
67
                         _mod_branch.format_registry.get_default())
 
68
 
 
69
 
 
70
class TestBranchFormat5(tests.TestCaseWithTransport):
89
71
    """Tests specific to branch format 5"""
90
72
 
91
73
    def test_branch_format_5_uses_lockdir(self):
92
74
        url = self.get_url()
93
 
        bzrdir = BzrDirMetaFormat1().initialize(url)
94
 
        bzrdir.create_repository()
95
 
        branch = bzrdir.create_branch()
 
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
 
76
        bdir.create_repository()
 
77
        branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
96
78
        t = self.get_transport()
97
79
        self.log("branch instance is %r" % branch)
98
 
        self.assert_(isinstance(branch, BzrBranch5))
 
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
99
81
        self.assertIsDirectory('.', t)
100
82
        self.assertIsDirectory('.bzr/branch', t)
101
83
        self.assertIsDirectory('.bzr/branch/lock', t)
102
84
        branch.lock_write()
103
 
        try:
104
 
            self.assertIsDirectory('.bzr/branch/lock/held', t)
105
 
        finally:
106
 
            branch.unlock()
 
85
        self.addCleanup(branch.unlock)
 
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
107
87
 
108
88
    def test_set_push_location(self):
109
 
        from bzrlib.config import (locations_config_filename,
110
 
                                   ensure_config_dir_exists)
111
 
        ensure_config_dir_exists()
112
 
        fn = locations_config_filename()
113
 
        # write correct newlines to locations.conf
114
 
        # by default ConfigObj uses native line-endings for new files
115
 
        # but uses already existing line-endings if file is not empty
116
 
        f = open(fn, 'wb')
117
 
        try:
118
 
            f.write('# comment\n')
119
 
        finally:
120
 
            f.close()
 
89
        conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
121
90
 
122
91
        branch = self.make_branch('.', format='knit')
123
92
        branch.set_push_location('foo')
126
95
                             "[%s]\n"
127
96
                             "push_location = foo\n"
128
97
                             "push_location:policy = norecurse\n" % local_path,
129
 
                             fn)
 
98
                             config.locations_config_filename())
130
99
 
131
100
    # TODO RBC 20051029 test getting a push location from a branch in a
132
101
    # recursive section - that is, it appends the branch name.
133
102
 
134
103
 
135
 
class SampleBranchFormat(BranchFormat):
 
104
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
136
105
    """A sample format
137
106
 
138
107
    this format is initializable, unsupported to aid in testing the
139
108
    open and open_downlevel routines.
140
109
    """
141
110
 
142
 
    def get_format_string(self):
 
111
    @classmethod
 
112
    def get_format_string(cls):
143
113
        """See BzrBranchFormat.get_format_string()."""
144
114
        return "Sample branch format."
145
115
 
146
 
    def initialize(self, a_bzrdir):
 
116
    def initialize(self, a_bzrdir, name=None, repository=None,
 
117
                   append_revisions_only=None):
147
118
        """Format 4 branches cannot be created."""
148
 
        t = a_bzrdir.get_branch_transport(self)
 
119
        t = a_bzrdir.get_branch_transport(self, name=name)
149
120
        t.put_bytes('format', self.get_format_string())
150
121
        return 'A branch'
151
122
 
152
123
    def is_supported(self):
153
124
        return False
154
125
 
155
 
    def open(self, transport, _found=False, ignore_fallbacks=False):
 
126
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
 
127
             possible_transports=None):
156
128
        return "opened branch."
157
129
 
158
130
 
159
 
class TestBzrBranchFormat(TestCaseWithTransport):
 
131
# Demonstrating how lazy loading is often implemented:
 
132
# A constant string is created.
 
133
SampleSupportedBranchFormatString = "Sample supported branch format."
 
134
 
 
135
# And the format class can then reference the constant to avoid skew.
 
136
class SampleSupportedBranchFormat(_mod_branch.BranchFormatMetadir):
 
137
    """A sample supported format."""
 
138
 
 
139
    @classmethod
 
140
    def get_format_string(cls):
 
141
        """See BzrBranchFormat.get_format_string()."""
 
142
        return SampleSupportedBranchFormatString
 
143
 
 
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())
 
147
        return 'A branch'
 
148
 
 
149
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
 
150
             possible_transports=None):
 
151
        return "opened supported branch."
 
152
 
 
153
 
 
154
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
 
155
    """A sample format that is not usable in a metadir."""
 
156
 
 
157
    def get_format_string(self):
 
158
        # This format is not usable in a metadir.
 
159
        return None
 
160
 
 
161
    def network_name(self):
 
162
        # Network name always has to be provided.
 
163
        return "extra"
 
164
 
 
165
    def initialize(self, a_bzrdir, name=None):
 
166
        raise NotImplementedError(self.initialize)
 
167
 
 
168
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
 
169
             possible_transports=None):
 
170
        raise NotImplementedError(self.open)
 
171
 
 
172
 
 
173
class TestBzrBranchFormat(tests.TestCaseWithTransport):
160
174
    """Tests for the BzrBranchFormat facility."""
161
175
 
162
176
    def test_find_format(self):
168
182
            dir = format._matchingbzrdir.initialize(url)
169
183
            dir.create_repository()
170
184
            format.initialize(dir)
171
 
            found_format = BranchFormat.find_format(dir)
172
 
            self.failUnless(isinstance(found_format, format.__class__))
173
 
        check_format(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")
 
188
 
 
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.")
 
199
 
 
200
    def test_from_string(self):
 
201
        self.assertIsInstance(
 
202
            SampleBranchFormat.from_string("Sample branch format."),
 
203
            SampleBranchFormat)
 
204
        self.assertRaises(ValueError,
 
205
            SampleBranchFormat.from_string, "Different branch format.")
174
206
 
175
207
    def test_find_format_not_branch(self):
176
208
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
177
 
        self.assertRaises(NotBranchError,
178
 
                          BranchFormat.find_format,
 
209
        self.assertRaises(errors.NotBranchError,
 
210
                          _mod_branch.BranchFormatMetadir.find_format,
179
211
                          dir)
180
212
 
181
213
    def test_find_format_unknown_format(self):
182
214
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
183
215
        SampleBranchFormat().initialize(dir)
184
 
        self.assertRaises(UnknownFormatError,
185
 
                          BranchFormat.find_format,
 
216
        self.assertRaises(errors.UnknownFormatError,
 
217
                          _mod_branch.BranchFormatMetadir.find_format,
186
218
                          dir)
187
219
 
188
220
    def test_register_unregister_format(self):
 
221
        # Test the deprecated format registration functions
189
222
        format = SampleBranchFormat()
190
223
        # make a control dir
191
224
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
192
225
        # make a branch
193
226
        format.initialize(dir)
194
227
        # register a format for it.
195
 
        BranchFormat.register_format(format)
 
228
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
229
            _mod_branch.BranchFormat.register_format, format)
196
230
        # which branch.Open will refuse (not supported)
197
 
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
 
231
        self.assertRaises(errors.UnsupportedFormatError,
 
232
                          _mod_branch.Branch.open, self.get_url())
198
233
        self.make_branch_and_tree('foo')
199
234
        # but open_downlevel will work
200
 
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
235
        self.assertEqual(
 
236
            format.open(dir),
 
237
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
201
238
        # unregister the format
202
 
        BranchFormat.unregister_format(format)
 
239
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
240
            _mod_branch.BranchFormat.unregister_format, format)
203
241
        self.make_branch_and_tree('bar')
204
242
 
205
243
 
 
244
class TestBranchFormatRegistry(tests.TestCase):
 
245
 
 
246
    def setUp(self):
 
247
        super(TestBranchFormatRegistry, self).setUp()
 
248
        self.registry = _mod_branch.BranchFormatRegistry()
 
249
 
 
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())
 
255
 
 
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.")
 
264
 
 
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())
 
270
 
 
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())
 
276
 
 
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)
 
284
 
 
285
 
 
286
#Used by TestMetaDirBranchFormatFactory 
 
287
FakeLazyFormat = None
 
288
 
 
289
 
 
290
class TestMetaDirBranchFormatFactory(tests.TestCase):
 
291
 
 
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())
 
296
 
 
297
    def test_call_loads(self):
 
298
        # __call__ is used by the network_format_registry interface to get a
 
299
        # Format.
 
300
        global FakeLazyFormat
 
301
        del FakeLazyFormat
 
302
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
 
303
            "bzrlib.tests.test_branch", "FakeLazyFormat")
 
304
        self.assertRaises(AttributeError, factory)
 
305
 
 
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())
 
312
 
 
313
 
206
314
class TestBranch67(object):
207
315
    """Common tests for both branch 6 and 7 which are mostly the same."""
208
316
 
216
324
        raise NotImplementedError(self.get_class)
217
325
 
218
326
    def test_creation(self):
219
 
        format = BzrDirMetaFormat1()
 
327
        format = bzrdir.BzrDirMetaFormat1()
220
328
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
221
329
        branch = self.make_branch('a', format=format)
222
330
        self.assertIsInstance(branch, self.get_class())
227
335
 
228
336
    def test_layout(self):
229
337
        branch = self.make_branch('a', format=self.get_format_name())
230
 
        self.failUnlessExists('a/.bzr/branch/last-revision')
231
 
        self.failIfExists('a/.bzr/branch/revision-history')
232
 
        self.failIfExists('a/.bzr/branch/references')
 
338
        self.assertPathExists('a/.bzr/branch/last-revision')
 
339
        self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
 
340
        self.assertPathDoesNotExist('a/.bzr/branch/references')
233
341
 
234
342
    def test_config(self):
235
343
        """Ensure that all configuration data is stored in the branch"""
236
344
        branch = self.make_branch('a', format=self.get_format_name())
237
 
        branch.set_parent('http://bazaar-vcs.org')
238
 
        self.failIfExists('a/.bzr/branch/parent')
239
 
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
240
 
        branch.set_push_location('sftp://bazaar-vcs.org')
 
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')
241
349
        config = branch.get_config()._get_branch_data_config()
242
 
        self.assertEqual('sftp://bazaar-vcs.org',
 
350
        self.assertEqual('sftp://example.com',
243
351
                         config.get_user_option('push_location'))
244
 
        branch.set_bound_location('ftp://bazaar-vcs.org')
245
 
        self.failIfExists('a/.bzr/branch/bound')
246
 
        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())
247
355
 
248
356
    def test_set_revision_history(self):
249
357
        builder = self.make_branch_builder('.', format=self.get_format_name())
254
362
        branch = builder.get_branch()
255
363
        branch.lock_write()
256
364
        self.addCleanup(branch.unlock)
257
 
        branch.set_revision_history(['foo', 'bar'])
258
 
        branch.set_revision_history(['foo'])
 
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'])
259
369
        self.assertRaises(errors.NotLefthandHistory,
260
 
                          branch.set_revision_history, ['bar'])
 
370
            self.applyDeprecated, symbol_versioning.deprecated_in((2, 4, 0)),
 
371
            branch.set_revision_history, ['bar'])
261
372
 
262
373
    def do_checkout_test(self, lightweight=False):
263
374
        tree = self.make_branch_and_tree('source',
276
387
        subtree.commit('a subtree file')
277
388
        subsubtree.commit('a subsubtree file')
278
389
        tree.branch.create_checkout('target', lightweight=lightweight)
279
 
        self.failUnlessExists('target')
280
 
        self.failUnlessExists('target/subtree')
281
 
        self.failUnlessExists('target/subtree/file')
282
 
        self.failUnlessExists('target/subtree/subsubtree/file')
 
390
        self.assertPathExists('target')
 
391
        self.assertPathExists('target/subtree')
 
392
        self.assertPathExists('target/subtree/file')
 
393
        self.assertPathExists('target/subtree/subsubtree/file')
283
394
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
284
395
        if lightweight:
285
396
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
309
420
                         'locations.conf')
310
421
 
311
422
 
312
 
class TestBranch6(TestBranch67, TestCaseWithTransport):
 
423
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
313
424
 
314
425
    def get_class(self):
315
426
        return _mod_branch.BzrBranch6
330
441
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
331
442
 
332
443
 
333
 
class TestBranch7(TestBranch67, TestCaseWithTransport):
 
444
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
334
445
 
335
446
    def get_class(self):
336
447
        return _mod_branch.BzrBranch7
380
491
        self.assertTrue(branch.repository.has_revision(revid))
381
492
 
382
493
 
383
 
class BzrBranch8(TestCaseWithTransport):
 
494
class BzrBranch8(tests.TestCaseWithTransport):
384
495
 
385
496
    def make_branch(self, location, format=None):
386
497
        if format is None:
387
498
            format = bzrdir.format_registry.make_bzrdir('1.9')
388
499
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
389
 
        return TestCaseWithTransport.make_branch(self, location, format=format)
 
500
        return tests.TestCaseWithTransport.make_branch(
 
501
            self, location, format=format)
390
502
 
391
503
    def create_branch_with_reference(self):
392
504
        branch = self.make_branch('branch')
436
548
        branch.lock_write()
437
549
        branch.set_reference_info('file-id', 'path2', 'location2')
438
550
        branch.unlock()
439
 
        doppelganger = Branch.open('branch')
 
551
        doppelganger = _mod_branch.Branch.open('branch')
440
552
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
441
553
        self.assertEqual(('path3', 'location3'),
442
554
                         branch.get_reference_info('file-id'))
443
555
 
444
 
class TestBranchReference(TestCaseWithTransport):
 
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):
 
560
            q = list(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
 
564
 
 
565
 
 
566
class TestBranchReference(tests.TestCaseWithTransport):
445
567
    """Tests for the branch reference facility."""
446
568
 
447
569
    def test_create_open_reference(self):
448
570
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
449
 
        t = get_transport(self.get_url('.'))
 
571
        t = self.get_transport()
450
572
        t.mkdir('repo')
451
573
        dir = bzrdirformat.initialize(self.get_url('repo'))
452
574
        dir.create_repository()
453
575
        target_branch = dir.create_branch()
454
576
        t.mkdir('branch')
455
577
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
456
 
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
 
578
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
 
579
            branch_dir, target_branch=target_branch)
457
580
        self.assertEqual(made_branch.base, target_branch.base)
458
581
        opened_branch = branch_dir.open_branch()
459
582
        self.assertEqual(opened_branch.base, target_branch.base)
470
593
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
471
594
 
472
595
 
473
 
class TestHooks(TestCase):
 
596
class TestHooks(tests.TestCaseWithTransport):
474
597
 
475
598
    def test_constructor(self):
476
599
        """Check that creating a BranchHooks instance has the right defaults."""
477
 
        hooks = BranchHooks()
 
600
        hooks = _mod_branch.BranchHooks()
478
601
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
479
602
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
480
603
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
481
604
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
482
605
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
483
 
        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)
484
608
        self.assertTrue("post_change_branch_tip" in hooks,
485
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)
486
614
 
487
615
    def test_installed_hooks_are_BranchHooks(self):
488
616
        """The installed hooks object should be a BranchHooks."""
489
617
        # the installed hooks are saved in self._preserved_hooks.
490
618
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
491
 
            BranchHooks)
492
 
 
493
 
 
494
 
class TestPullResult(TestCase):
 
619
                              _mod_branch.BranchHooks)
 
620
 
 
621
    def test_post_branch_init_hook(self):
 
622
        calls = []
 
623
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
 
624
            calls.append, None)
 
625
        self.assertLength(0, calls)
 
626
        branch = self.make_branch('a')
 
627
        self.assertLength(1, calls)
 
628
        params = calls[0]
 
629
        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
 
630
        self.assertTrue(hasattr(params, 'bzrdir'))
 
631
        self.assertTrue(hasattr(params, 'branch'))
 
632
 
 
633
    def test_post_branch_init_hook_repr(self):
 
634
        param_reprs = []
 
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 ')
 
641
 
 
642
    def test_post_switch_hook(self):
 
643
        from bzrlib import switch
 
644
        calls = []
 
645
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
 
646
            calls.append, None)
 
647
        tree = self.make_branch_and_tree('branch-1')
 
648
        self.build_tree(['branch-1/file-1'])
 
649
        tree.add('file-1')
 
650
        tree.commit('rev1')
 
651
        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
 
652
        self.build_tree(['branch-1/file-2'])
 
653
        tree.add('file-2')
 
654
        tree.remove('file-1')
 
655
        tree.commit('rev2')
 
656
        checkout = tree.branch.create_checkout('checkout')
 
657
        self.assertLength(0, calls)
 
658
        switch.switch(checkout.bzrdir, to_branch)
 
659
        self.assertLength(1, calls)
 
660
        params = calls[0]
 
661
        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
 
662
        self.assertTrue(hasattr(params, 'to_branch'))
 
663
        self.assertTrue(hasattr(params, 'revision_id'))
 
664
 
 
665
 
 
666
class TestBranchOptions(tests.TestCaseWithTransport):
 
667
 
 
668
    def setUp(self):
 
669
        super(TestBranchOptions, self).setUp()
 
670
        self.branch = self.make_branch('.')
 
671
        self.config_stack = self.branch.get_config_stack()
 
672
 
 
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())
 
679
 
 
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')
 
690
 
 
691
    def test_invalid_append_revisions_only(self):
 
692
        """Ensure warning is noted on invalid settings"""
 
693
        self.warnings = []
 
694
        def warning(*args):
 
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)
 
699
        self.assertEqual(
 
700
            'Value "not-a-bool" is not valid for "append_revisions_only"',
 
701
            self.warnings[0])
 
702
 
 
703
 
 
704
class TestPullResult(tests.TestCase):
495
705
 
496
706
    def test_pull_result_to_int(self):
497
707
        # to support old code, the pull result can be used as an int
498
 
        r = PullResult()
 
708
        r = _mod_branch.PullResult()
499
709
        r.old_revno = 10
500
710
        r.new_revno = 20
501
711
        # this usage of results is not recommended for new code (because it
502
712
        # doesn't describe very well what happened), but for api stability
503
713
        # it's still supported
504
 
        a = "%d revisions pulled" % r
505
 
        self.assertEqual(a, "10 revisions pulled")
 
714
        self.assertEqual(self.applyDeprecated(
 
715
            symbol_versioning.deprecated_in((2, 3, 0)),
 
716
            r.__int__),
 
717
            10)
506
718
 
507
719
    def test_report_changed(self):
508
 
        r = PullResult()
 
720
        r = _mod_branch.PullResult()
509
721
        r.old_revid = "old-revid"
510
722
        r.old_revno = 10
511
723
        r.new_revid = "new-revid"
513
725
        f = StringIO()
514
726
        r.report(f)
515
727
        self.assertEqual("Now on revision 20.\n", f.getvalue())
 
728
        self.assertEqual("Now on revision 20.\n", f.getvalue())
516
729
 
517
730
    def test_report_unchanged(self):
518
 
        r = PullResult()
 
731
        r = _mod_branch.PullResult()
519
732
        r.old_revid = "same-revid"
520
733
        r.new_revid = "same-revid"
521
734
        f = StringIO()
522
735
        r.report(f)
523
 
        self.assertEqual("No revisions to pull.\n", f.getvalue())
524
 
 
525
 
 
526
 
class _StubLockable(object):
527
 
    """Helper for TestRunWithWriteLockedTarget."""
528
 
 
529
 
    def __init__(self, calls, unlock_exc=None):
530
 
        self.calls = calls
531
 
        self.unlock_exc = unlock_exc
532
 
 
533
 
    def lock_write(self):
534
 
        self.calls.append('lock_write')
535
 
 
536
 
    def unlock(self):
537
 
        self.calls.append('unlock')
538
 
        if self.unlock_exc is not None:
539
 
            raise self.unlock_exc
540
 
 
541
 
 
542
 
class _ErrorFromCallable(Exception):
543
 
    """Helper for TestRunWithWriteLockedTarget."""
544
 
 
545
 
 
546
 
class _ErrorFromUnlock(Exception):
547
 
    """Helper for TestRunWithWriteLockedTarget."""
548
 
 
549
 
 
550
 
class TestRunWithWriteLockedTarget(TestCase):
551
 
    """Tests for _run_with_write_locked_target."""
552
 
 
553
 
    def setUp(self):
554
 
        TestCase.setUp(self)
555
 
        self._calls = []
556
 
 
557
 
    def func_that_returns_ok(self):
558
 
        self._calls.append('func called')
559
 
        return 'ok'
560
 
 
561
 
    def func_that_raises(self):
562
 
        self._calls.append('func called')
563
 
        raise _ErrorFromCallable()
564
 
 
565
 
    def test_success_unlocks(self):
566
 
        lockable = _StubLockable(self._calls)
567
 
        result = _run_with_write_locked_target(
568
 
            lockable, self.func_that_returns_ok)
569
 
        self.assertEqual('ok', result)
570
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
571
 
 
572
 
    def test_exception_unlocks_and_propagates(self):
573
 
        lockable = _StubLockable(self._calls)
574
 
        self.assertRaises(_ErrorFromCallable,
575
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
576
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
577
 
 
578
 
    def test_callable_succeeds_but_error_during_unlock(self):
579
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
580
 
        self.assertRaises(_ErrorFromUnlock,
581
 
            _run_with_write_locked_target, lockable, self.func_that_returns_ok)
582
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
583
 
 
584
 
    def test_error_during_unlock_does_not_mask_original_error(self):
585
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
586
 
        self.assertRaises(_ErrorFromCallable,
587
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
588
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
589
 
 
 
736
        self.assertEqual("No revisions or tags to pull.\n", f.getvalue())
590
737