~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 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/branch_implementations/*.py.
 
19
For interface tests see tests/per_branch/*.py.
20
20
 
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
23
23
"""
24
24
 
25
 
from StringIO import StringIO
 
25
from cStringIO import StringIO
26
26
 
27
27
from bzrlib import (
28
28
    branch as _mod_branch,
29
29
    bzrdir,
30
30
    config,
31
31
    errors,
 
32
    tests,
32
33
    trace,
 
34
    transport,
33
35
    urlutils,
34
36
    )
35
 
from bzrlib.branch import (
36
 
    Branch,
37
 
    BranchHooks,
38
 
    BranchFormat,
39
 
    BranchReferenceFormat,
40
 
    BzrBranch5,
41
 
    BzrBranchFormat5,
42
 
    BzrBranchFormat6,
43
 
    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):
 
37
 
 
38
 
 
39
class TestDefaultFormat(tests.TestCase):
59
40
 
60
41
    def test_default_format(self):
61
42
        # update this if you change the default branch format
62
 
        self.assertIsInstance(BranchFormat.get_default_format(),
63
 
                BzrBranchFormat6)
 
43
        self.assertIsInstance(_mod_branch.BranchFormat.get_default_format(),
 
44
                _mod_branch.BzrBranchFormat7)
64
45
 
65
46
    def test_default_format_is_same_as_bzrdir_default(self):
66
47
        # XXX: it might be nice if there was only one place the default was
67
48
        # set, but at the moment that's not true -- mbp 20070814 --
68
49
        # https://bugs.launchpad.net/bzr/+bug/132376
69
 
        self.assertEqual(BranchFormat.get_default_format(),
70
 
                BzrDirFormat.get_default_format().get_branch_format())
 
50
        self.assertEqual(
 
51
            _mod_branch.BranchFormat.get_default_format(),
 
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
71
53
 
72
54
    def test_get_set_default_format(self):
73
55
        # set the format and then set it back again
74
 
        old_format = BranchFormat.get_default_format()
75
 
        BranchFormat.set_default_format(SampleBranchFormat())
 
56
        old_format = _mod_branch.BranchFormat.get_default_format()
 
57
        _mod_branch.BranchFormat.set_default_format(SampleBranchFormat())
76
58
        try:
77
59
            # the default branch format is used by the meta dir format
78
60
            # which is not the default bzrdir format at this point
79
 
            dir = BzrDirMetaFormat1().initialize('memory:///')
 
61
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
80
62
            result = dir.create_branch()
81
63
            self.assertEqual(result, 'A branch')
82
64
        finally:
83
 
            BranchFormat.set_default_format(old_format)
84
 
        self.assertEqual(old_format, BranchFormat.get_default_format())
85
 
 
86
 
 
87
 
class TestBranchFormat5(TestCaseWithTransport):
 
65
            _mod_branch.BranchFormat.set_default_format(old_format)
 
66
        self.assertEqual(old_format,
 
67
                         _mod_branch.BranchFormat.get_default_format())
 
68
 
 
69
 
 
70
class TestBranchFormat5(tests.TestCaseWithTransport):
88
71
    """Tests specific to branch format 5"""
89
72
 
90
73
    def test_branch_format_5_uses_lockdir(self):
91
74
        url = self.get_url()
92
 
        bzrdir = BzrDirMetaFormat1().initialize(url)
93
 
        bzrdir.create_repository()
94
 
        branch = bzrdir.create_branch()
 
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
 
76
        bdir.create_repository()
 
77
        branch = bdir.create_branch()
95
78
        t = self.get_transport()
96
79
        self.log("branch instance is %r" % branch)
97
 
        self.assert_(isinstance(branch, BzrBranch5))
 
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
98
81
        self.assertIsDirectory('.', t)
99
82
        self.assertIsDirectory('.bzr/branch', t)
100
83
        self.assertIsDirectory('.bzr/branch/lock', t)
101
84
        branch.lock_write()
102
 
        try:
103
 
            self.assertIsDirectory('.bzr/branch/lock/held', t)
104
 
        finally:
105
 
            branch.unlock()
 
85
        self.addCleanup(branch.unlock)
 
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
106
87
 
107
88
    def test_set_push_location(self):
108
89
        from bzrlib.config import (locations_config_filename,
131
112
    # recursive section - that is, it appends the branch name.
132
113
 
133
114
 
134
 
class SampleBranchFormat(BranchFormat):
 
115
class SampleBranchFormat(_mod_branch.BranchFormat):
135
116
    """A sample format
136
117
 
137
118
    this format is initializable, unsupported to aid in testing the
142
123
        """See BzrBranchFormat.get_format_string()."""
143
124
        return "Sample branch format."
144
125
 
145
 
    def initialize(self, a_bzrdir):
 
126
    def initialize(self, a_bzrdir, name=None):
146
127
        """Format 4 branches cannot be created."""
147
 
        t = a_bzrdir.get_branch_transport(self)
 
128
        t = a_bzrdir.get_branch_transport(self, name=name)
148
129
        t.put_bytes('format', self.get_format_string())
149
130
        return 'A branch'
150
131
 
151
132
    def is_supported(self):
152
133
        return False
153
134
 
154
 
    def open(self, transport, _found=False, ignore_fallbacks=False):
 
135
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
155
136
        return "opened branch."
156
137
 
157
138
 
158
 
class TestBzrBranchFormat(TestCaseWithTransport):
 
139
# Demonstrating how lazy loading is often implemented:
 
140
# A constant string is created.
 
141
SampleSupportedBranchFormatString = "Sample supported branch format."
 
142
 
 
143
# And the format class can then reference the constant to avoid skew.
 
144
class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
 
145
    """A sample supported format."""
 
146
 
 
147
    def get_format_string(self):
 
148
        """See BzrBranchFormat.get_format_string()."""
 
149
        return SampleSupportedBranchFormatString
 
150
 
 
151
    def initialize(self, a_bzrdir, name=None):
 
152
        t = a_bzrdir.get_branch_transport(self, name=name)
 
153
        t.put_bytes('format', self.get_format_string())
 
154
        return 'A branch'
 
155
 
 
156
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
 
157
        return "opened supported branch."
 
158
 
 
159
 
 
160
class TestBzrBranchFormat(tests.TestCaseWithTransport):
159
161
    """Tests for the BzrBranchFormat facility."""
160
162
 
161
163
    def test_find_format(self):
167
169
            dir = format._matchingbzrdir.initialize(url)
168
170
            dir.create_repository()
169
171
            format.initialize(dir)
170
 
            found_format = BranchFormat.find_format(dir)
 
172
            found_format = _mod_branch.BranchFormat.find_format(dir)
171
173
            self.failUnless(isinstance(found_format, format.__class__))
172
 
        check_format(BzrBranchFormat5(), "bar")
 
174
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
 
175
 
 
176
    def test_find_format_factory(self):
 
177
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
178
        SampleSupportedBranchFormat().initialize(dir)
 
179
        factory = _mod_branch.MetaDirBranchFormatFactory(
 
180
            SampleSupportedBranchFormatString,
 
181
            "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
 
182
        _mod_branch.BranchFormat.register_format(factory)
 
183
        self.addCleanup(_mod_branch.BranchFormat.unregister_format, factory)
 
184
        b = _mod_branch.Branch.open(self.get_url())
 
185
        self.assertEqual(b, "opened supported branch.")
173
186
 
174
187
    def test_find_format_not_branch(self):
175
188
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
176
 
        self.assertRaises(NotBranchError,
177
 
                          BranchFormat.find_format,
 
189
        self.assertRaises(errors.NotBranchError,
 
190
                          _mod_branch.BranchFormat.find_format,
178
191
                          dir)
179
192
 
180
193
    def test_find_format_unknown_format(self):
181
194
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
182
195
        SampleBranchFormat().initialize(dir)
183
 
        self.assertRaises(UnknownFormatError,
184
 
                          BranchFormat.find_format,
 
196
        self.assertRaises(errors.UnknownFormatError,
 
197
                          _mod_branch.BranchFormat.find_format,
185
198
                          dir)
186
199
 
187
200
    def test_register_unregister_format(self):
191
204
        # make a branch
192
205
        format.initialize(dir)
193
206
        # register a format for it.
194
 
        BranchFormat.register_format(format)
 
207
        _mod_branch.BranchFormat.register_format(format)
195
208
        # which branch.Open will refuse (not supported)
196
 
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
 
209
        self.assertRaises(errors.UnsupportedFormatError,
 
210
                          _mod_branch.Branch.open, self.get_url())
197
211
        self.make_branch_and_tree('foo')
198
212
        # but open_downlevel will work
199
 
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
213
        self.assertEqual(
 
214
            format.open(dir),
 
215
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
200
216
        # unregister the format
201
 
        BranchFormat.unregister_format(format)
 
217
        _mod_branch.BranchFormat.unregister_format(format)
202
218
        self.make_branch_and_tree('bar')
203
219
 
204
220
 
 
221
#Used by TestMetaDirBranchFormatFactory 
 
222
FakeLazyFormat = None
 
223
 
 
224
 
 
225
class TestMetaDirBranchFormatFactory(tests.TestCase):
 
226
 
 
227
    def test_get_format_string_does_not_load(self):
 
228
        """Formats have a static format string."""
 
229
        factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
 
230
        self.assertEqual("yo", factory.get_format_string())
 
231
 
 
232
    def test_call_loads(self):
 
233
        # __call__ is used by the network_format_registry interface to get a
 
234
        # Format.
 
235
        global FakeLazyFormat
 
236
        del FakeLazyFormat
 
237
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
 
238
            "bzrlib.tests.test_branch", "FakeLazyFormat")
 
239
        self.assertRaises(AttributeError, factory)
 
240
 
 
241
    def test_call_returns_call_of_referenced_object(self):
 
242
        global FakeLazyFormat
 
243
        FakeLazyFormat = lambda:'called'
 
244
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
 
245
            "bzrlib.tests.test_branch", "FakeLazyFormat")
 
246
        self.assertEqual('called', factory())
 
247
 
 
248
 
205
249
class TestBranch67(object):
206
250
    """Common tests for both branch 6 and 7 which are mostly the same."""
207
251
 
215
259
        raise NotImplementedError(self.get_class)
216
260
 
217
261
    def test_creation(self):
218
 
        format = BzrDirMetaFormat1()
 
262
        format = bzrdir.BzrDirMetaFormat1()
219
263
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
220
264
        branch = self.make_branch('a', format=format)
221
265
        self.assertIsInstance(branch, self.get_class())
228
272
        branch = self.make_branch('a', format=self.get_format_name())
229
273
        self.failUnlessExists('a/.bzr/branch/last-revision')
230
274
        self.failIfExists('a/.bzr/branch/revision-history')
 
275
        self.failIfExists('a/.bzr/branch/references')
231
276
 
232
277
    def test_config(self):
233
278
        """Ensure that all configuration data is stored in the branch"""
307
352
                         'locations.conf')
308
353
 
309
354
 
310
 
class TestBranch6(TestBranch67, TestCaseWithTransport):
 
355
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
311
356
 
312
357
    def get_class(self):
313
358
        return _mod_branch.BzrBranch6
328
373
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
329
374
 
330
375
 
331
 
class TestBranch7(TestBranch67, TestCaseWithTransport):
 
376
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
332
377
 
333
378
    def get_class(self):
334
379
        return _mod_branch.BzrBranch7
378
423
        self.assertTrue(branch.repository.has_revision(revid))
379
424
 
380
425
 
381
 
class TestBranchReference(TestCaseWithTransport):
 
426
class BzrBranch8(tests.TestCaseWithTransport):
 
427
 
 
428
    def make_branch(self, location, format=None):
 
429
        if format is None:
 
430
            format = bzrdir.format_registry.make_bzrdir('1.9')
 
431
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
 
432
        return tests.TestCaseWithTransport.make_branch(
 
433
            self, location, format=format)
 
434
 
 
435
    def create_branch_with_reference(self):
 
436
        branch = self.make_branch('branch')
 
437
        branch._set_all_reference_info({'file-id': ('path', 'location')})
 
438
        return branch
 
439
 
 
440
    @staticmethod
 
441
    def instrument_branch(branch, gets):
 
442
        old_get = branch._transport.get
 
443
        def get(*args, **kwargs):
 
444
            gets.append((args, kwargs))
 
445
            return old_get(*args, **kwargs)
 
446
        branch._transport.get = get
 
447
 
 
448
    def test_reference_info_caching_read_locked(self):
 
449
        gets = []
 
450
        branch = self.create_branch_with_reference()
 
451
        branch.lock_read()
 
452
        self.addCleanup(branch.unlock)
 
453
        self.instrument_branch(branch, gets)
 
454
        branch.get_reference_info('file-id')
 
455
        branch.get_reference_info('file-id')
 
456
        self.assertEqual(1, len(gets))
 
457
 
 
458
    def test_reference_info_caching_read_unlocked(self):
 
459
        gets = []
 
460
        branch = self.create_branch_with_reference()
 
461
        self.instrument_branch(branch, gets)
 
462
        branch.get_reference_info('file-id')
 
463
        branch.get_reference_info('file-id')
 
464
        self.assertEqual(2, len(gets))
 
465
 
 
466
    def test_reference_info_caching_write_locked(self):
 
467
        gets = []
 
468
        branch = self.make_branch('branch')
 
469
        branch.lock_write()
 
470
        self.instrument_branch(branch, gets)
 
471
        self.addCleanup(branch.unlock)
 
472
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
 
473
        path, location = branch.get_reference_info('file-id')
 
474
        self.assertEqual(0, len(gets))
 
475
        self.assertEqual('path2', path)
 
476
        self.assertEqual('location2', location)
 
477
 
 
478
    def test_reference_info_caches_cleared(self):
 
479
        branch = self.make_branch('branch')
 
480
        branch.lock_write()
 
481
        branch.set_reference_info('file-id', 'path2', 'location2')
 
482
        branch.unlock()
 
483
        doppelganger = _mod_branch.Branch.open('branch')
 
484
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
 
485
        self.assertEqual(('path3', 'location3'),
 
486
                         branch.get_reference_info('file-id'))
 
487
 
 
488
class TestBranchReference(tests.TestCaseWithTransport):
382
489
    """Tests for the branch reference facility."""
383
490
 
384
491
    def test_create_open_reference(self):
385
492
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
386
 
        t = get_transport(self.get_url('.'))
 
493
        t = transport.get_transport(self.get_url('.'))
387
494
        t.mkdir('repo')
388
495
        dir = bzrdirformat.initialize(self.get_url('repo'))
389
496
        dir.create_repository()
390
497
        target_branch = dir.create_branch()
391
498
        t.mkdir('branch')
392
499
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
393
 
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
 
500
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
 
501
            branch_dir, target_branch=target_branch)
394
502
        self.assertEqual(made_branch.base, target_branch.base)
395
503
        opened_branch = branch_dir.open_branch()
396
504
        self.assertEqual(opened_branch.base, target_branch.base)
407
515
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
408
516
 
409
517
 
410
 
class TestHooks(TestCase):
 
518
class TestHooks(tests.TestCaseWithTransport):
411
519
 
412
520
    def test_constructor(self):
413
521
        """Check that creating a BranchHooks instance has the right defaults."""
414
 
        hooks = BranchHooks()
 
522
        hooks = _mod_branch.BranchHooks()
415
523
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
416
524
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
417
525
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
418
526
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
419
527
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
420
 
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
 
528
        self.assertTrue("post_uncommit" in hooks,
 
529
                        "post_uncommit not in %s" % hooks)
421
530
        self.assertTrue("post_change_branch_tip" in hooks,
422
531
                        "post_change_branch_tip not in %s" % hooks)
 
532
        self.assertTrue("post_branch_init" in hooks,
 
533
                        "post_branch_init not in %s" % hooks)
 
534
        self.assertTrue("post_switch" in hooks,
 
535
                        "post_switch not in %s" % hooks)
423
536
 
424
537
    def test_installed_hooks_are_BranchHooks(self):
425
538
        """The installed hooks object should be a BranchHooks."""
426
539
        # the installed hooks are saved in self._preserved_hooks.
427
540
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
428
 
            BranchHooks)
429
 
 
430
 
 
431
 
class TestPullResult(TestCase):
 
541
                              _mod_branch.BranchHooks)
 
542
 
 
543
    def test_post_branch_init_hook(self):
 
544
        calls = []
 
545
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
 
546
            calls.append, None)
 
547
        self.assertLength(0, calls)
 
548
        branch = self.make_branch('a')
 
549
        self.assertLength(1, calls)
 
550
        params = calls[0]
 
551
        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
 
552
        self.assertTrue(hasattr(params, 'bzrdir'))
 
553
        self.assertTrue(hasattr(params, 'branch'))
 
554
 
 
555
    def test_post_switch_hook(self):
 
556
        from bzrlib import switch
 
557
        calls = []
 
558
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
 
559
            calls.append, None)
 
560
        tree = self.make_branch_and_tree('branch-1')
 
561
        self.build_tree(['branch-1/file-1'])
 
562
        tree.add('file-1')
 
563
        tree.commit('rev1')
 
564
        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
 
565
        self.build_tree(['branch-1/file-2'])
 
566
        tree.add('file-2')
 
567
        tree.remove('file-1')
 
568
        tree.commit('rev2')
 
569
        checkout = tree.branch.create_checkout('checkout')
 
570
        self.assertLength(0, calls)
 
571
        switch.switch(checkout.bzrdir, to_branch)
 
572
        self.assertLength(1, calls)
 
573
        params = calls[0]
 
574
        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
 
575
        self.assertTrue(hasattr(params, 'to_branch'))
 
576
        self.assertTrue(hasattr(params, 'revision_id'))
 
577
 
 
578
 
 
579
class TestBranchOptions(tests.TestCaseWithTransport):
 
580
 
 
581
    def setUp(self):
 
582
        super(TestBranchOptions, self).setUp()
 
583
        self.branch = self.make_branch('.')
 
584
        self.config = self.branch.get_config()
 
585
 
 
586
    def check_append_revisions_only(self, expected_value, value=None):
 
587
        """Set append_revisions_only in config and check its interpretation."""
 
588
        if value is not None:
 
589
            self.config.set_user_option('append_revisions_only', value)
 
590
        self.assertEqual(expected_value,
 
591
                         self.branch._get_append_revisions_only())
 
592
 
 
593
    def test_valid_append_revisions_only(self):
 
594
        self.assertEquals(None,
 
595
                          self.config.get_user_option('append_revisions_only'))
 
596
        self.check_append_revisions_only(None)
 
597
        self.check_append_revisions_only(False, 'False')
 
598
        self.check_append_revisions_only(True, 'True')
 
599
        # The following values will cause compatibility problems on projects
 
600
        # using older bzr versions (<2.2) but are accepted
 
601
        self.check_append_revisions_only(False, 'false')
 
602
        self.check_append_revisions_only(True, 'true')
 
603
 
 
604
    def test_invalid_append_revisions_only(self):
 
605
        """Ensure warning is noted on invalid settings"""
 
606
        self.warnings = []
 
607
        def warning(*args):
 
608
            self.warnings.append(args[0] % args[1:])
 
609
        self.overrideAttr(trace, 'warning', warning)
 
610
        self.check_append_revisions_only(None, 'not-a-bool')
 
611
        self.assertLength(1, self.warnings)
 
612
        self.assertEqual(
 
613
            'Value "not-a-bool" is not a boolean for "append_revisions_only"',
 
614
            self.warnings[0])
 
615
 
 
616
 
 
617
class TestPullResult(tests.TestCase):
432
618
 
433
619
    def test_pull_result_to_int(self):
434
620
        # to support old code, the pull result can be used as an int
435
 
        r = PullResult()
 
621
        r = _mod_branch.PullResult()
436
622
        r.old_revno = 10
437
623
        r.new_revno = 20
438
624
        # this usage of results is not recommended for new code (because it
441
627
        a = "%d revisions pulled" % r
442
628
        self.assertEqual(a, "10 revisions pulled")
443
629
 
 
630
    def test_report_changed(self):
 
631
        r = _mod_branch.PullResult()
 
632
        r.old_revid = "old-revid"
 
633
        r.old_revno = 10
 
634
        r.new_revid = "new-revid"
 
635
        r.new_revno = 20
 
636
        f = StringIO()
 
637
        r.report(f)
 
638
        self.assertEqual("Now on revision 20.\n", f.getvalue())
 
639
 
 
640
    def test_report_unchanged(self):
 
641
        r = _mod_branch.PullResult()
 
642
        r.old_revid = "same-revid"
 
643
        r.new_revid = "same-revid"
 
644
        f = StringIO()
 
645
        r.report(f)
 
646
        self.assertEqual("No revisions to pull.\n", f.getvalue())
444
647
 
445
648
 
446
649
class _StubLockable(object):
467
670
    """Helper for TestRunWithWriteLockedTarget."""
468
671
 
469
672
 
470
 
class TestRunWithWriteLockedTarget(TestCase):
 
673
class TestRunWithWriteLockedTarget(tests.TestCase):
471
674
    """Tests for _run_with_write_locked_target."""
472
675
 
473
676
    def setUp(self):
474
 
        TestCase.setUp(self)
 
677
        tests.TestCase.setUp(self)
475
678
        self._calls = []
476
679
 
477
680
    def func_that_returns_ok(self):
484
687
 
485
688
    def test_success_unlocks(self):
486
689
        lockable = _StubLockable(self._calls)
487
 
        result = _run_with_write_locked_target(
 
690
        result = _mod_branch._run_with_write_locked_target(
488
691
            lockable, self.func_that_returns_ok)
489
692
        self.assertEqual('ok', result)
490
693
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
492
695
    def test_exception_unlocks_and_propagates(self):
493
696
        lockable = _StubLockable(self._calls)
494
697
        self.assertRaises(_ErrorFromCallable,
495
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
 
698
                          _mod_branch._run_with_write_locked_target,
 
699
                          lockable, self.func_that_raises)
496
700
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
497
701
 
498
702
    def test_callable_succeeds_but_error_during_unlock(self):
499
703
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
500
704
        self.assertRaises(_ErrorFromUnlock,
501
 
            _run_with_write_locked_target, lockable, self.func_that_returns_ok)
 
705
                          _mod_branch._run_with_write_locked_target,
 
706
                          lockable, self.func_that_returns_ok)
502
707
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
503
708
 
504
709
    def test_error_during_unlock_does_not_mask_original_error(self):
505
710
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
506
711
        self.assertRaises(_ErrorFromCallable,
507
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
 
712
                          _mod_branch._run_with_write_locked_target,
 
713
                          lockable, self.func_that_raises)
508
714
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
509
715
 
510
716