~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Andrew Bennetts
  • Date: 2009-04-02 05:53:12 UTC
  • mto: This revision was merged to the branch mainline in revision 4242.
  • Revision ID: andrew.bennetts@canonical.com-20090402055312-h7mvgumvm7e620mj
Fix nits in spelling and naming.

Show diffs side-by-side

added added

removed removed

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