~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-08 08:15:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101008081514-dviqzrdfwyzsqbz2
Split NEWS into per-release doc/en/release-notes/bzr-*.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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.
28
28
    branch as _mod_branch,
29
29
    bzrdir,
30
30
    config,
31
 
    controldir,
32
31
    errors,
 
32
    symbol_versioning,
33
33
    tests,
34
34
    trace,
 
35
    transport,
35
36
    urlutils,
36
37
    )
37
 
from bzrlib.branchfmt.fullhistory import (
38
 
    BzrBranch5,
39
 
    BzrBranchFormat5,
40
 
    )
41
38
 
42
39
 
43
40
class TestDefaultFormat(tests.TestCase):
44
41
 
45
42
    def test_default_format(self):
46
43
        # update this if you change the default branch format
47
 
        self.assertIsInstance(_mod_branch.format_registry.get_default(),
 
44
        self.assertIsInstance(_mod_branch.BranchFormat.get_default_format(),
48
45
                _mod_branch.BzrBranchFormat7)
49
46
 
50
47
    def test_default_format_is_same_as_bzrdir_default(self):
52
49
        # set, but at the moment that's not true -- mbp 20070814 --
53
50
        # https://bugs.launchpad.net/bzr/+bug/132376
54
51
        self.assertEqual(
55
 
            _mod_branch.format_registry.get_default(),
 
52
            _mod_branch.BranchFormat.get_default_format(),
56
53
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
57
54
 
58
55
    def test_get_set_default_format(self):
59
56
        # set the format and then set it back again
60
 
        old_format = _mod_branch.format_registry.get_default()
61
 
        _mod_branch.format_registry.set_default(SampleBranchFormat())
 
57
        old_format = _mod_branch.BranchFormat.get_default_format()
 
58
        _mod_branch.BranchFormat.set_default_format(SampleBranchFormat())
62
59
        try:
63
60
            # the default branch format is used by the meta dir format
64
61
            # which is not the default bzrdir format at this point
66
63
            result = dir.create_branch()
67
64
            self.assertEqual(result, 'A branch')
68
65
        finally:
69
 
            _mod_branch.format_registry.set_default(old_format)
 
66
            _mod_branch.BranchFormat.set_default_format(old_format)
70
67
        self.assertEqual(old_format,
71
 
                         _mod_branch.format_registry.get_default())
 
68
                         _mod_branch.BranchFormat.get_default_format())
72
69
 
73
70
 
74
71
class TestBranchFormat5(tests.TestCaseWithTransport):
78
75
        url = self.get_url()
79
76
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
80
77
        bdir.create_repository()
81
 
        branch = BzrBranchFormat5().initialize(bdir)
 
78
        branch = bdir.create_branch()
82
79
        t = self.get_transport()
83
80
        self.log("branch instance is %r" % branch)
84
 
        self.assertTrue(isinstance(branch, BzrBranch5))
 
81
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
85
82
        self.assertIsDirectory('.', t)
86
83
        self.assertIsDirectory('.bzr/branch', t)
87
84
        self.assertIsDirectory('.bzr/branch/lock', t)
105
102
    # recursive section - that is, it appends the branch name.
106
103
 
107
104
 
108
 
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
 
105
class SampleBranchFormat(_mod_branch.BranchFormat):
109
106
    """A sample format
110
107
 
111
108
    this format is initializable, unsupported to aid in testing the
112
109
    open and open_downlevel routines.
113
110
    """
114
111
 
115
 
    @classmethod
116
 
    def get_format_string(cls):
 
112
    def get_format_string(self):
117
113
        """See BzrBranchFormat.get_format_string()."""
118
114
        return "Sample branch format."
119
115
 
120
 
    def initialize(self, a_bzrdir, name=None, repository=None,
121
 
                   append_revisions_only=None):
 
116
    def initialize(self, a_bzrdir, name=None):
122
117
        """Format 4 branches cannot be created."""
123
118
        t = a_bzrdir.get_branch_transport(self, name=name)
124
119
        t.put_bytes('format', self.get_format_string())
127
122
    def is_supported(self):
128
123
        return False
129
124
 
130
 
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
131
 
             possible_transports=None):
 
125
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
132
126
        return "opened branch."
133
127
 
134
128
 
137
131
SampleSupportedBranchFormatString = "Sample supported branch format."
138
132
 
139
133
# And the format class can then reference the constant to avoid skew.
140
 
class SampleSupportedBranchFormat(_mod_branch.BranchFormatMetadir):
 
134
class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
141
135
    """A sample supported format."""
142
136
 
143
 
    @classmethod
144
 
    def get_format_string(cls):
 
137
    def get_format_string(self):
145
138
        """See BzrBranchFormat.get_format_string()."""
146
139
        return SampleSupportedBranchFormatString
147
140
 
148
 
    def initialize(self, a_bzrdir, name=None, append_revisions_only=None):
 
141
    def initialize(self, a_bzrdir, name=None):
149
142
        t = a_bzrdir.get_branch_transport(self, name=name)
150
143
        t.put_bytes('format', self.get_format_string())
151
144
        return 'A branch'
152
145
 
153
 
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
154
 
             possible_transports=None):
 
146
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
155
147
        return "opened supported branch."
156
148
 
157
149
 
158
 
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
159
 
    """A sample format that is not usable in a metadir."""
160
 
 
161
 
    def get_format_string(self):
162
 
        # This format is not usable in a metadir.
163
 
        return None
164
 
 
165
 
    def network_name(self):
166
 
        # Network name always has to be provided.
167
 
        return "extra"
168
 
 
169
 
    def initialize(self, a_bzrdir, name=None):
170
 
        raise NotImplementedError(self.initialize)
171
 
 
172
 
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
173
 
             possible_transports=None):
174
 
        raise NotImplementedError(self.open)
175
 
 
176
 
 
177
150
class TestBzrBranchFormat(tests.TestCaseWithTransport):
178
151
    """Tests for the BzrBranchFormat facility."""
179
152
 
186
159
            dir = format._matchingbzrdir.initialize(url)
187
160
            dir.create_repository()
188
161
            format.initialize(dir)
189
 
            found_format = _mod_branch.BranchFormatMetadir.find_format(dir)
190
 
            self.assertIsInstance(found_format, format.__class__)
191
 
        check_format(BzrBranchFormat5(), "bar")
 
162
            found_format = _mod_branch.BranchFormat.find_format(dir)
 
163
            self.failUnless(isinstance(found_format, format.__class__))
 
164
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
192
165
 
193
166
    def test_find_format_factory(self):
194
167
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
196
169
        factory = _mod_branch.MetaDirBranchFormatFactory(
197
170
            SampleSupportedBranchFormatString,
198
171
            "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
199
 
        _mod_branch.format_registry.register(factory)
200
 
        self.addCleanup(_mod_branch.format_registry.remove, factory)
 
172
        _mod_branch.BranchFormat.register_format(factory)
 
173
        self.addCleanup(_mod_branch.BranchFormat.unregister_format, factory)
201
174
        b = _mod_branch.Branch.open(self.get_url())
202
175
        self.assertEqual(b, "opened supported branch.")
203
176
 
204
 
    def test_from_string(self):
205
 
        self.assertIsInstance(
206
 
            SampleBranchFormat.from_string("Sample branch format."),
207
 
            SampleBranchFormat)
208
 
        self.assertRaises(AssertionError,
209
 
            SampleBranchFormat.from_string, "Different branch format.")
210
 
 
211
177
    def test_find_format_not_branch(self):
212
178
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
213
179
        self.assertRaises(errors.NotBranchError,
214
 
                          _mod_branch.BranchFormatMetadir.find_format,
 
180
                          _mod_branch.BranchFormat.find_format,
215
181
                          dir)
216
182
 
217
183
    def test_find_format_unknown_format(self):
218
184
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
219
185
        SampleBranchFormat().initialize(dir)
220
186
        self.assertRaises(errors.UnknownFormatError,
221
 
                          _mod_branch.BranchFormatMetadir.find_format,
 
187
                          _mod_branch.BranchFormat.find_format,
222
188
                          dir)
223
189
 
224
 
    def test_find_format_with_features(self):
225
 
        tree = self.make_branch_and_tree('.', format='2a')
226
 
        tree.branch.update_feature_flags({"name": "optional"})
227
 
        found_format = _mod_branch.BranchFormatMetadir.find_format(tree.bzrdir)
228
 
        self.assertIsInstance(found_format, _mod_branch.BranchFormatMetadir)
229
 
        self.assertEqual(found_format.features.get("name"), "optional")
230
 
        tree.branch.update_feature_flags({"name": None})
231
 
        branch = _mod_branch.Branch.open('.')
232
 
        self.assertEqual(branch._format.features, {})
233
 
 
234
 
 
235
 
class TestBranchFormatRegistry(tests.TestCase):
236
 
 
237
 
    def setUp(self):
238
 
        super(TestBranchFormatRegistry, self).setUp()
239
 
        self.registry = _mod_branch.BranchFormatRegistry()
240
 
 
241
 
    def test_default(self):
242
 
        self.assertIs(None, self.registry.get_default())
243
 
        format = SampleBranchFormat()
244
 
        self.registry.set_default(format)
245
 
        self.assertEqual(format, self.registry.get_default())
246
 
 
247
190
    def test_register_unregister_format(self):
248
191
        format = SampleBranchFormat()
249
 
        self.registry.register(format)
250
 
        self.assertEqual(format,
251
 
            self.registry.get("Sample branch format."))
252
 
        self.registry.remove(format)
253
 
        self.assertRaises(KeyError, self.registry.get,
254
 
            "Sample branch format.")
255
 
 
256
 
    def test_get_all(self):
257
 
        format = SampleBranchFormat()
258
 
        self.assertEqual([], self.registry._get_all())
259
 
        self.registry.register(format)
260
 
        self.assertEqual([format], self.registry._get_all())
261
 
 
262
 
    def test_register_extra(self):
263
 
        format = SampleExtraBranchFormat()
264
 
        self.assertEqual([], self.registry._get_all())
265
 
        self.registry.register_extra(format)
266
 
        self.assertEqual([format], self.registry._get_all())
267
 
 
268
 
    def test_register_extra_lazy(self):
269
 
        self.assertEqual([], self.registry._get_all())
270
 
        self.registry.register_extra_lazy("bzrlib.tests.test_branch",
271
 
            "SampleExtraBranchFormat")
272
 
        formats = self.registry._get_all()
273
 
        self.assertEqual(1, len(formats))
274
 
        self.assertIsInstance(formats[0], SampleExtraBranchFormat)
 
192
        # make a control dir
 
193
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
194
        # make a branch
 
195
        format.initialize(dir)
 
196
        # register a format for it.
 
197
        _mod_branch.BranchFormat.register_format(format)
 
198
        # which branch.Open will refuse (not supported)
 
199
        self.assertRaises(errors.UnsupportedFormatError,
 
200
                          _mod_branch.Branch.open, self.get_url())
 
201
        self.make_branch_and_tree('foo')
 
202
        # but open_downlevel will work
 
203
        self.assertEqual(
 
204
            format.open(dir),
 
205
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
206
        # unregister the format
 
207
        _mod_branch.BranchFormat.unregister_format(format)
 
208
        self.make_branch_and_tree('bar')
275
209
 
276
210
 
277
211
#Used by TestMetaDirBranchFormatFactory 
326
260
 
327
261
    def test_layout(self):
328
262
        branch = self.make_branch('a', format=self.get_format_name())
329
 
        self.assertPathExists('a/.bzr/branch/last-revision')
330
 
        self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
331
 
        self.assertPathDoesNotExist('a/.bzr/branch/references')
 
263
        self.failUnlessExists('a/.bzr/branch/last-revision')
 
264
        self.failIfExists('a/.bzr/branch/revision-history')
 
265
        self.failIfExists('a/.bzr/branch/references')
332
266
 
333
267
    def test_config(self):
334
268
        """Ensure that all configuration data is stored in the branch"""
335
269
        branch = self.make_branch('a', format=self.get_format_name())
336
 
        branch.set_parent('http://example.com')
337
 
        self.assertPathDoesNotExist('a/.bzr/branch/parent')
338
 
        self.assertEqual('http://example.com', branch.get_parent())
339
 
        branch.set_push_location('sftp://example.com')
340
 
        conf = branch.get_config_stack()
341
 
        self.assertEqual('sftp://example.com', conf.get('push_location'))
342
 
        branch.set_bound_location('ftp://example.com')
343
 
        self.assertPathDoesNotExist('a/.bzr/branch/bound')
344
 
        self.assertEqual('ftp://example.com', branch.get_bound_location())
 
270
        branch.set_parent('http://bazaar-vcs.org')
 
271
        self.failIfExists('a/.bzr/branch/parent')
 
272
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
 
273
        branch.set_push_location('sftp://bazaar-vcs.org')
 
274
        config = branch.get_config()._get_branch_data_config()
 
275
        self.assertEqual('sftp://bazaar-vcs.org',
 
276
                         config.get_user_option('push_location'))
 
277
        branch.set_bound_location('ftp://bazaar-vcs.org')
 
278
        self.failIfExists('a/.bzr/branch/bound')
 
279
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
 
280
 
 
281
    def test_set_revision_history(self):
 
282
        builder = self.make_branch_builder('.', format=self.get_format_name())
 
283
        builder.build_snapshot('foo', None,
 
284
            [('add', ('', None, 'directory', None))],
 
285
            message='foo')
 
286
        builder.build_snapshot('bar', None, [], message='bar')
 
287
        branch = builder.get_branch()
 
288
        branch.lock_write()
 
289
        self.addCleanup(branch.unlock)
 
290
        branch.set_revision_history(['foo', 'bar'])
 
291
        branch.set_revision_history(['foo'])
 
292
        self.assertRaises(errors.NotLefthandHistory,
 
293
                          branch.set_revision_history, ['bar'])
345
294
 
346
295
    def do_checkout_test(self, lightweight=False):
347
296
        tree = self.make_branch_and_tree('source',
360
309
        subtree.commit('a subtree file')
361
310
        subsubtree.commit('a subsubtree file')
362
311
        tree.branch.create_checkout('target', lightweight=lightweight)
363
 
        self.assertPathExists('target')
364
 
        self.assertPathExists('target/subtree')
365
 
        self.assertPathExists('target/subtree/file')
366
 
        self.assertPathExists('target/subtree/subsubtree/file')
 
312
        self.failUnlessExists('target')
 
313
        self.failUnlessExists('target/subtree')
 
314
        self.failUnlessExists('target/subtree/file')
 
315
        self.failUnlessExists('target/subtree/subsubtree/file')
367
316
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
368
317
        if lightweight:
369
318
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
376
325
    def test_light_checkout_with_references(self):
377
326
        self.do_checkout_test(lightweight=True)
378
327
 
 
328
    def test_set_push(self):
 
329
        branch = self.make_branch('source', format=self.get_format_name())
 
330
        branch.get_config().set_user_option('push_location', 'old',
 
331
            store=config.STORE_LOCATION)
 
332
        warnings = []
 
333
        def warning(*args):
 
334
            warnings.append(args[0] % args[1:])
 
335
        _warning = trace.warning
 
336
        trace.warning = warning
 
337
        try:
 
338
            branch.set_push_location('new')
 
339
        finally:
 
340
            trace.warning = _warning
 
341
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
 
342
                         'locations.conf')
 
343
 
379
344
 
380
345
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
381
346
 
452
417
 
453
418
    def make_branch(self, location, format=None):
454
419
        if format is None:
455
 
            format = controldir.format_registry.make_bzrdir('1.9')
 
420
            format = bzrdir.format_registry.make_bzrdir('1.9')
456
421
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
457
422
        return tests.TestCaseWithTransport.make_branch(
458
423
            self, location, format=format)
510
475
        self.assertEqual(('path3', 'location3'),
511
476
                         branch.get_reference_info('file-id'))
512
477
 
513
 
    def _recordParentMapCalls(self, repo):
514
 
        self._parent_map_calls = []
515
 
        orig_get_parent_map = repo.revisions.get_parent_map
516
 
        def get_parent_map(q):
517
 
            q = list(q)
518
 
            self._parent_map_calls.extend([e[0] for e in q])
519
 
            return orig_get_parent_map(q)
520
 
        repo.revisions.get_parent_map = get_parent_map
521
 
 
522
 
 
523
478
class TestBranchReference(tests.TestCaseWithTransport):
524
479
    """Tests for the branch reference facility."""
525
480
 
526
481
    def test_create_open_reference(self):
527
482
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
528
 
        t = self.get_transport()
 
483
        t = transport.get_transport(self.get_url('.'))
529
484
        t.mkdir('repo')
530
485
        dir = bzrdirformat.initialize(self.get_url('repo'))
531
486
        dir.create_repository()
539
494
        self.assertEqual(opened_branch.base, target_branch.base)
540
495
 
541
496
    def test_get_reference(self):
542
 
        """For a BranchReference, get_reference should return the location."""
 
497
        """For a BranchReference, get_reference should reutrn the location."""
543
498
        branch = self.make_branch('target')
544
499
        checkout = branch.create_checkout('checkout', lightweight=True)
545
500
        reference_url = branch.bzrdir.root_transport.abspath('') + '/'
555
510
    def test_constructor(self):
556
511
        """Check that creating a BranchHooks instance has the right defaults."""
557
512
        hooks = _mod_branch.BranchHooks()
 
513
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
558
514
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
559
515
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
560
516
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
624
580
    def setUp(self):
625
581
        super(TestBranchOptions, self).setUp()
626
582
        self.branch = self.make_branch('.')
627
 
        self.config_stack = self.branch.get_config_stack()
 
583
        self.config = self.branch.get_config()
628
584
 
629
585
    def check_append_revisions_only(self, expected_value, value=None):
630
586
        """Set append_revisions_only in config and check its interpretation."""
631
587
        if value is not None:
632
 
            self.config_stack.set('append_revisions_only', value)
 
588
            self.config.set_user_option('append_revisions_only', value)
633
589
        self.assertEqual(expected_value,
634
 
                         self.branch.get_append_revisions_only())
 
590
                         self.branch._get_append_revisions_only())
635
591
 
636
592
    def test_valid_append_revisions_only(self):
637
 
        self.assertEqual(None,
638
 
                          self.config_stack.get('append_revisions_only'))
 
593
        self.assertEquals(None,
 
594
                          self.config.get_user_option('append_revisions_only'))
639
595
        self.check_append_revisions_only(None)
640
596
        self.check_append_revisions_only(False, 'False')
641
597
        self.check_append_revisions_only(True, 'True')
653
609
        self.check_append_revisions_only(None, 'not-a-bool')
654
610
        self.assertLength(1, self.warnings)
655
611
        self.assertEqual(
656
 
            'Value "not-a-bool" is not valid for "append_revisions_only"',
 
612
            'Value "not-a-bool" is not a boolean for "append_revisions_only"',
657
613
            self.warnings[0])
658
614
 
659
 
    def test_use_fresh_values(self):
660
 
        copy = _mod_branch.Branch.open(self.branch.base)
661
 
        copy.lock_write()
662
 
        try:
663
 
            copy.get_config_stack().set('foo', 'bar')
664
 
        finally:
665
 
            copy.unlock()
666
 
        self.assertFalse(self.branch.is_locked())
667
 
        # Since the branch is locked, the option value won't be saved on disk
668
 
        # so trying to access the config of locked branch via another older
669
 
        # non-locked branch object pointing to the same branch is not supported
670
 
        self.assertEqual(None, self.branch.get_config_stack().get('foo'))
671
 
        # Using a newly created branch object works as expected
672
 
        fresh = _mod_branch.Branch.open(self.branch.base)
673
 
        self.assertEqual('bar', fresh.get_config_stack().get('foo'))
674
 
 
675
 
    def test_set_from_config_get_from_config_stack(self):
676
 
        self.branch.lock_write()
677
 
        self.addCleanup(self.branch.unlock)
678
 
        self.branch.get_config().set_user_option('foo', 'bar')
679
 
        result = self.branch.get_config_stack().get('foo')
680
 
        # https://bugs.launchpad.net/bzr/+bug/948344
681
 
        self.expectFailure('BranchStack uses cache after set_user_option',
682
 
                           self.assertEqual, 'bar', result)
683
 
 
684
 
    def test_set_from_config_stack_get_from_config(self):
685
 
        self.branch.lock_write()
686
 
        self.addCleanup(self.branch.unlock)
687
 
        self.branch.get_config_stack().set('foo', 'bar')
688
 
        # Since the branch is locked, the option value won't be saved on disk
689
 
        # so mixing get() and get_user_option() is broken by design.
690
 
        self.assertEqual(None,
691
 
                         self.branch.get_config().get_user_option('foo'))
692
 
 
693
 
    def test_set_delays_write_when_branch_is_locked(self):
694
 
        self.branch.lock_write()
695
 
        self.addCleanup(self.branch.unlock)
696
 
        self.branch.get_config_stack().set('foo', 'bar')
697
 
        copy = _mod_branch.Branch.open(self.branch.base)
698
 
        result = copy.get_config_stack().get('foo')
699
 
        # Accessing from a different branch object is like accessing from a
700
 
        # different process: the option has not been saved yet and the new
701
 
        # value cannot be seen.
702
 
        self.assertIs(None, result)
703
 
 
704
615
 
705
616
class TestPullResult(tests.TestCase):
706
617
 
 
618
    def test_pull_result_to_int(self):
 
619
        # to support old code, the pull result can be used as an int
 
620
        r = _mod_branch.PullResult()
 
621
        r.old_revno = 10
 
622
        r.new_revno = 20
 
623
        # this usage of results is not recommended for new code (because it
 
624
        # doesn't describe very well what happened), but for api stability
 
625
        # it's still supported
 
626
        self.assertEqual(self.applyDeprecated(
 
627
            symbol_versioning.deprecated_in((2, 3, 0)),
 
628
            r.__int__),
 
629
            10)
 
630
 
707
631
    def test_report_changed(self):
708
632
        r = _mod_branch.PullResult()
709
633
        r.old_revid = "old-revid"
713
637
        f = StringIO()
714
638
        r.report(f)
715
639
        self.assertEqual("Now on revision 20.\n", f.getvalue())
716
 
        self.assertEqual("Now on revision 20.\n", f.getvalue())
717
640
 
718
641
    def test_report_unchanged(self):
719
642
        r = _mod_branch.PullResult()
721
644
        r.new_revid = "same-revid"
722
645
        f = StringIO()
723
646
        r.report(f)
724
 
        self.assertEqual("No revisions or tags to pull.\n", f.getvalue())
 
647
        self.assertEqual("No revisions to pull.\n", f.getvalue())
 
648
 
 
649
 
 
650
class _StubLockable(object):
 
651
    """Helper for TestRunWithWriteLockedTarget."""
 
652
 
 
653
    def __init__(self, calls, unlock_exc=None):
 
654
        self.calls = calls
 
655
        self.unlock_exc = unlock_exc
 
656
 
 
657
    def lock_write(self):
 
658
        self.calls.append('lock_write')
 
659
 
 
660
    def unlock(self):
 
661
        self.calls.append('unlock')
 
662
        if self.unlock_exc is not None:
 
663
            raise self.unlock_exc
 
664
 
 
665
 
 
666
class _ErrorFromCallable(Exception):
 
667
    """Helper for TestRunWithWriteLockedTarget."""
 
668
 
 
669
 
 
670
class _ErrorFromUnlock(Exception):
 
671
    """Helper for TestRunWithWriteLockedTarget."""
 
672
 
 
673
 
 
674
class TestRunWithWriteLockedTarget(tests.TestCase):
 
675
    """Tests for _run_with_write_locked_target."""
 
676
 
 
677
    def setUp(self):
 
678
        tests.TestCase.setUp(self)
 
679
        self._calls = []
 
680
 
 
681
    def func_that_returns_ok(self):
 
682
        self._calls.append('func called')
 
683
        return 'ok'
 
684
 
 
685
    def func_that_raises(self):
 
686
        self._calls.append('func called')
 
687
        raise _ErrorFromCallable()
 
688
 
 
689
    def test_success_unlocks(self):
 
690
        lockable = _StubLockable(self._calls)
 
691
        result = _mod_branch._run_with_write_locked_target(
 
692
            lockable, self.func_that_returns_ok)
 
693
        self.assertEqual('ok', result)
 
694
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
695
 
 
696
    def test_exception_unlocks_and_propagates(self):
 
697
        lockable = _StubLockable(self._calls)
 
698
        self.assertRaises(_ErrorFromCallable,
 
699
                          _mod_branch._run_with_write_locked_target,
 
700
                          lockable, self.func_that_raises)
 
701
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
702
 
 
703
    def test_callable_succeeds_but_error_during_unlock(self):
 
704
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
705
        self.assertRaises(_ErrorFromUnlock,
 
706
                          _mod_branch._run_with_write_locked_target,
 
707
                          lockable, self.func_that_returns_ok)
 
708
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
709
 
 
710
    def test_error_during_unlock_does_not_mask_original_error(self):
 
711
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
712
        self.assertRaises(_ErrorFromCallable,
 
713
                          _mod_branch._run_with_write_locked_target,
 
714
                          lockable, self.func_that_raises)
 
715
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
716
 
 
717