~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: John Arbash Meinel
  • Date: 2010-01-05 04:30:07 UTC
  • mfrom: (4932 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4934.
  • Revision ID: john@arbash-meinel.com-20100105043007-ehgbldqd3q0gtyws
Merge bzr.dev, resolve conflicts.

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