~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Vincent Ladeuil
  • Date: 2010-03-10 09:33:04 UTC
  • mto: (5082.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5083.
  • Revision ID: v.ladeuil+lp@free.fr-20100310093304-4245t4tazd4sxoav
Cleanup test from overly cautious checks.

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,
33
32
    tests,
34
33
    trace,
 
34
    transport,
35
35
    urlutils,
36
36
    )
37
 
from bzrlib.branchfmt.fullhistory import (
38
 
    BzrBranch5,
39
 
    BzrBranchFormat5,
40
 
    )
41
37
 
42
38
 
43
39
class TestDefaultFormat(tests.TestCase):
44
40
 
45
41
    def test_default_format(self):
46
42
        # update this if you change the default branch format
47
 
        self.assertIsInstance(_mod_branch.format_registry.get_default(),
 
43
        self.assertIsInstance(_mod_branch.BranchFormat.get_default_format(),
48
44
                _mod_branch.BzrBranchFormat7)
49
45
 
50
46
    def test_default_format_is_same_as_bzrdir_default(self):
52
48
        # set, but at the moment that's not true -- mbp 20070814 --
53
49
        # https://bugs.launchpad.net/bzr/+bug/132376
54
50
        self.assertEqual(
55
 
            _mod_branch.format_registry.get_default(),
 
51
            _mod_branch.BranchFormat.get_default_format(),
56
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
57
53
 
58
54
    def test_get_set_default_format(self):
59
55
        # 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())
 
56
        old_format = _mod_branch.BranchFormat.get_default_format()
 
57
        _mod_branch.BranchFormat.set_default_format(SampleBranchFormat())
62
58
        try:
63
59
            # the default branch format is used by the meta dir format
64
60
            # which is not the default bzrdir format at this point
66
62
            result = dir.create_branch()
67
63
            self.assertEqual(result, 'A branch')
68
64
        finally:
69
 
            _mod_branch.format_registry.set_default(old_format)
 
65
            _mod_branch.BranchFormat.set_default_format(old_format)
70
66
        self.assertEqual(old_format,
71
 
                         _mod_branch.format_registry.get_default())
 
67
                         _mod_branch.BranchFormat.get_default_format())
72
68
 
73
69
 
74
70
class TestBranchFormat5(tests.TestCaseWithTransport):
78
74
        url = self.get_url()
79
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
80
76
        bdir.create_repository()
81
 
        branch = BzrBranchFormat5().initialize(bdir)
 
77
        branch = bdir.create_branch()
82
78
        t = self.get_transport()
83
79
        self.log("branch instance is %r" % branch)
84
 
        self.assertTrue(isinstance(branch, BzrBranch5))
 
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
85
81
        self.assertIsDirectory('.', t)
86
82
        self.assertIsDirectory('.bzr/branch', t)
87
83
        self.assertIsDirectory('.bzr/branch/lock', t)
90
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
91
87
 
92
88
    def test_set_push_location(self):
93
 
        conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
 
89
        from bzrlib.config import (locations_config_filename,
 
90
                                   ensure_config_dir_exists)
 
91
        ensure_config_dir_exists()
 
92
        fn = locations_config_filename()
 
93
        # write correct newlines to locations.conf
 
94
        # by default ConfigObj uses native line-endings for new files
 
95
        # but uses already existing line-endings if file is not empty
 
96
        f = open(fn, 'wb')
 
97
        try:
 
98
            f.write('# comment\n')
 
99
        finally:
 
100
            f.close()
94
101
 
95
102
        branch = self.make_branch('.', format='knit')
96
103
        branch.set_push_location('foo')
99
106
                             "[%s]\n"
100
107
                             "push_location = foo\n"
101
108
                             "push_location:policy = norecurse\n" % local_path,
102
 
                             config.locations_config_filename())
 
109
                             fn)
103
110
 
104
111
    # TODO RBC 20051029 test getting a push location from a branch in a
105
112
    # recursive section - that is, it appends the branch name.
106
113
 
107
114
 
108
 
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
 
115
class SampleBranchFormat(_mod_branch.BranchFormat):
109
116
    """A sample format
110
117
 
111
118
    this format is initializable, unsupported to aid in testing the
112
119
    open and open_downlevel routines.
113
120
    """
114
121
 
115
 
    @classmethod
116
 
    def get_format_string(cls):
 
122
    def get_format_string(self):
117
123
        """See BzrBranchFormat.get_format_string()."""
118
124
        return "Sample branch format."
119
125
 
120
 
    def initialize(self, a_bzrdir, name=None, repository=None,
121
 
                   append_revisions_only=None):
 
126
    def initialize(self, a_bzrdir):
122
127
        """Format 4 branches cannot be created."""
123
 
        t = a_bzrdir.get_branch_transport(self, name=name)
 
128
        t = a_bzrdir.get_branch_transport(self)
124
129
        t.put_bytes('format', self.get_format_string())
125
130
        return 'A branch'
126
131
 
127
132
    def is_supported(self):
128
133
        return False
129
134
 
130
 
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
131
 
             possible_transports=None):
 
135
    def open(self, transport, _found=False, ignore_fallbacks=False):
132
136
        return "opened branch."
133
137
 
134
138
 
135
 
# Demonstrating how lazy loading is often implemented:
136
 
# A constant string is created.
137
 
SampleSupportedBranchFormatString = "Sample supported branch format."
138
 
 
139
 
# And the format class can then reference the constant to avoid skew.
140
 
class SampleSupportedBranchFormat(_mod_branch.BranchFormatMetadir):
141
 
    """A sample supported format."""
142
 
 
143
 
    @classmethod
144
 
    def get_format_string(cls):
145
 
        """See BzrBranchFormat.get_format_string()."""
146
 
        return SampleSupportedBranchFormatString
147
 
 
148
 
    def initialize(self, a_bzrdir, name=None, append_revisions_only=None):
149
 
        t = a_bzrdir.get_branch_transport(self, name=name)
150
 
        t.put_bytes('format', self.get_format_string())
151
 
        return 'A branch'
152
 
 
153
 
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
154
 
             possible_transports=None):
155
 
        return "opened supported branch."
156
 
 
157
 
 
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
139
class TestBzrBranchFormat(tests.TestCaseWithTransport):
178
140
    """Tests for the BzrBranchFormat facility."""
179
141
 
186
148
            dir = format._matchingbzrdir.initialize(url)
187
149
            dir.create_repository()
188
150
            format.initialize(dir)
189
 
            found_format = _mod_branch.BranchFormatMetadir.find_format(dir)
190
 
            self.assertIsInstance(found_format, format.__class__)
191
 
        check_format(BzrBranchFormat5(), "bar")
192
 
 
193
 
    def test_find_format_factory(self):
194
 
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
195
 
        SampleSupportedBranchFormat().initialize(dir)
196
 
        factory = _mod_branch.MetaDirBranchFormatFactory(
197
 
            SampleSupportedBranchFormatString,
198
 
            "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
199
 
        _mod_branch.format_registry.register(factory)
200
 
        self.addCleanup(_mod_branch.format_registry.remove, factory)
201
 
        b = _mod_branch.Branch.open(self.get_url())
202
 
        self.assertEqual(b, "opened supported branch.")
203
 
 
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.")
 
151
            found_format = _mod_branch.BranchFormat.find_format(dir)
 
152
            self.failUnless(isinstance(found_format, format.__class__))
 
153
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
210
154
 
211
155
    def test_find_format_not_branch(self):
212
156
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
213
157
        self.assertRaises(errors.NotBranchError,
214
 
                          _mod_branch.BranchFormatMetadir.find_format,
 
158
                          _mod_branch.BranchFormat.find_format,
215
159
                          dir)
216
160
 
217
161
    def test_find_format_unknown_format(self):
218
162
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
219
163
        SampleBranchFormat().initialize(dir)
220
164
        self.assertRaises(errors.UnknownFormatError,
221
 
                          _mod_branch.BranchFormatMetadir.find_format,
 
165
                          _mod_branch.BranchFormat.find_format,
222
166
                          dir)
223
167
 
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
168
    def test_register_unregister_format(self):
248
169
        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)
275
 
 
276
 
 
277
 
#Used by TestMetaDirBranchFormatFactory 
278
 
FakeLazyFormat = None
279
 
 
280
 
 
281
 
class TestMetaDirBranchFormatFactory(tests.TestCase):
282
 
 
283
 
    def test_get_format_string_does_not_load(self):
284
 
        """Formats have a static format string."""
285
 
        factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
286
 
        self.assertEqual("yo", factory.get_format_string())
287
 
 
288
 
    def test_call_loads(self):
289
 
        # __call__ is used by the network_format_registry interface to get a
290
 
        # Format.
291
 
        global FakeLazyFormat
292
 
        del FakeLazyFormat
293
 
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
294
 
            "bzrlib.tests.test_branch", "FakeLazyFormat")
295
 
        self.assertRaises(AttributeError, factory)
296
 
 
297
 
    def test_call_returns_call_of_referenced_object(self):
298
 
        global FakeLazyFormat
299
 
        FakeLazyFormat = lambda:'called'
300
 
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
301
 
            "bzrlib.tests.test_branch", "FakeLazyFormat")
302
 
        self.assertEqual('called', factory())
 
170
        # make a control dir
 
171
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
172
        # make a branch
 
173
        format.initialize(dir)
 
174
        # register a format for it.
 
175
        _mod_branch.BranchFormat.register_format(format)
 
176
        # which branch.Open will refuse (not supported)
 
177
        self.assertRaises(errors.UnsupportedFormatError,
 
178
                          _mod_branch.Branch.open, self.get_url())
 
179
        self.make_branch_and_tree('foo')
 
180
        # but open_downlevel will work
 
181
        self.assertEqual(
 
182
            format.open(dir),
 
183
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
184
        # unregister the format
 
185
        _mod_branch.BranchFormat.unregister_format(format)
 
186
        self.make_branch_and_tree('bar')
303
187
 
304
188
 
305
189
class TestBranch67(object):
326
210
 
327
211
    def test_layout(self):
328
212
        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')
 
213
        self.failUnlessExists('a/.bzr/branch/last-revision')
 
214
        self.failIfExists('a/.bzr/branch/revision-history')
 
215
        self.failIfExists('a/.bzr/branch/references')
332
216
 
333
217
    def test_config(self):
334
218
        """Ensure that all configuration data is stored in the branch"""
335
219
        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())
 
220
        branch.set_parent('http://bazaar-vcs.org')
 
221
        self.failIfExists('a/.bzr/branch/parent')
 
222
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
 
223
        branch.set_push_location('sftp://bazaar-vcs.org')
 
224
        config = branch.get_config()._get_branch_data_config()
 
225
        self.assertEqual('sftp://bazaar-vcs.org',
 
226
                         config.get_user_option('push_location'))
 
227
        branch.set_bound_location('ftp://bazaar-vcs.org')
 
228
        self.failIfExists('a/.bzr/branch/bound')
 
229
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
 
230
 
 
231
    def test_set_revision_history(self):
 
232
        builder = self.make_branch_builder('.', format=self.get_format_name())
 
233
        builder.build_snapshot('foo', None,
 
234
            [('add', ('', None, 'directory', None))],
 
235
            message='foo')
 
236
        builder.build_snapshot('bar', None, [], message='bar')
 
237
        branch = builder.get_branch()
 
238
        branch.lock_write()
 
239
        self.addCleanup(branch.unlock)
 
240
        branch.set_revision_history(['foo', 'bar'])
 
241
        branch.set_revision_history(['foo'])
 
242
        self.assertRaises(errors.NotLefthandHistory,
 
243
                          branch.set_revision_history, ['bar'])
345
244
 
346
245
    def do_checkout_test(self, lightweight=False):
347
246
        tree = self.make_branch_and_tree('source',
360
259
        subtree.commit('a subtree file')
361
260
        subsubtree.commit('a subsubtree file')
362
261
        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')
 
262
        self.failUnlessExists('target')
 
263
        self.failUnlessExists('target/subtree')
 
264
        self.failUnlessExists('target/subtree/file')
 
265
        self.failUnlessExists('target/subtree/subsubtree/file')
367
266
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
368
267
        if lightweight:
369
268
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
376
275
    def test_light_checkout_with_references(self):
377
276
        self.do_checkout_test(lightweight=True)
378
277
 
 
278
    def test_set_push(self):
 
279
        branch = self.make_branch('source', format=self.get_format_name())
 
280
        branch.get_config().set_user_option('push_location', 'old',
 
281
            store=config.STORE_LOCATION)
 
282
        warnings = []
 
283
        def warning(*args):
 
284
            warnings.append(args[0] % args[1:])
 
285
        _warning = trace.warning
 
286
        trace.warning = warning
 
287
        try:
 
288
            branch.set_push_location('new')
 
289
        finally:
 
290
            trace.warning = _warning
 
291
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
 
292
                         'locations.conf')
 
293
 
379
294
 
380
295
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
381
296
 
452
367
 
453
368
    def make_branch(self, location, format=None):
454
369
        if format is None:
455
 
            format = controldir.format_registry.make_bzrdir('1.9')
 
370
            format = bzrdir.format_registry.make_bzrdir('1.9')
456
371
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
457
372
        return tests.TestCaseWithTransport.make_branch(
458
373
            self, location, format=format)
510
425
        self.assertEqual(('path3', 'location3'),
511
426
                         branch.get_reference_info('file-id'))
512
427
 
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
428
class TestBranchReference(tests.TestCaseWithTransport):
524
429
    """Tests for the branch reference facility."""
525
430
 
526
431
    def test_create_open_reference(self):
527
432
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
528
 
        t = self.get_transport()
 
433
        t = transport.get_transport(self.get_url('.'))
529
434
        t.mkdir('repo')
530
435
        dir = bzrdirformat.initialize(self.get_url('repo'))
531
436
        dir.create_repository()
533
438
        t.mkdir('branch')
534
439
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
535
440
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
536
 
            branch_dir, target_branch=target_branch)
 
441
            branch_dir, target_branch)
537
442
        self.assertEqual(made_branch.base, target_branch.base)
538
443
        opened_branch = branch_dir.open_branch()
539
444
        self.assertEqual(opened_branch.base, target_branch.base)
540
445
 
541
446
    def test_get_reference(self):
542
 
        """For a BranchReference, get_reference should return the location."""
 
447
        """For a BranchReference, get_reference should reutrn the location."""
543
448
        branch = self.make_branch('target')
544
449
        checkout = branch.create_checkout('checkout', lightweight=True)
545
450
        reference_url = branch.bzrdir.root_transport.abspath('') + '/'
550
455
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
551
456
 
552
457
 
553
 
class TestHooks(tests.TestCaseWithTransport):
 
458
class TestHooks(tests.TestCase):
554
459
 
555
460
    def test_constructor(self):
556
461
        """Check that creating a BranchHooks instance has the right defaults."""
557
462
        hooks = _mod_branch.BranchHooks()
 
463
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
558
464
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
559
465
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
560
466
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
563
469
                        "post_uncommit not in %s" % hooks)
564
470
        self.assertTrue("post_change_branch_tip" in hooks,
565
471
                        "post_change_branch_tip not in %s" % hooks)
566
 
        self.assertTrue("post_branch_init" in hooks,
567
 
                        "post_branch_init not in %s" % hooks)
568
 
        self.assertTrue("post_switch" in hooks,
569
 
                        "post_switch not in %s" % hooks)
570
472
 
571
473
    def test_installed_hooks_are_BranchHooks(self):
572
474
        """The installed hooks object should be a BranchHooks."""
574
476
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
575
477
                              _mod_branch.BranchHooks)
576
478
 
577
 
    def test_post_branch_init_hook(self):
578
 
        calls = []
579
 
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
580
 
            calls.append, None)
581
 
        self.assertLength(0, calls)
582
 
        branch = self.make_branch('a')
583
 
        self.assertLength(1, calls)
584
 
        params = calls[0]
585
 
        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
586
 
        self.assertTrue(hasattr(params, 'bzrdir'))
587
 
        self.assertTrue(hasattr(params, 'branch'))
588
 
 
589
 
    def test_post_branch_init_hook_repr(self):
590
 
        param_reprs = []
591
 
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
592
 
            lambda params: param_reprs.append(repr(params)), None)
593
 
        branch = self.make_branch('a')
594
 
        self.assertLength(1, param_reprs)
595
 
        param_repr = param_reprs[0]
596
 
        self.assertStartsWith(param_repr, '<BranchInitHookParams of ')
597
 
 
598
 
    def test_post_switch_hook(self):
599
 
        from bzrlib import switch
600
 
        calls = []
601
 
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
602
 
            calls.append, None)
603
 
        tree = self.make_branch_and_tree('branch-1')
604
 
        self.build_tree(['branch-1/file-1'])
605
 
        tree.add('file-1')
606
 
        tree.commit('rev1')
607
 
        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
608
 
        self.build_tree(['branch-1/file-2'])
609
 
        tree.add('file-2')
610
 
        tree.remove('file-1')
611
 
        tree.commit('rev2')
612
 
        checkout = tree.branch.create_checkout('checkout')
613
 
        self.assertLength(0, calls)
614
 
        switch.switch(checkout.bzrdir, to_branch)
615
 
        self.assertLength(1, calls)
616
 
        params = calls[0]
617
 
        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
618
 
        self.assertTrue(hasattr(params, 'to_branch'))
619
 
        self.assertTrue(hasattr(params, 'revision_id'))
620
 
 
621
 
 
622
 
class TestBranchOptions(tests.TestCaseWithTransport):
623
 
 
624
 
    def setUp(self):
625
 
        super(TestBranchOptions, self).setUp()
626
 
        self.branch = self.make_branch('.')
627
 
        self.config_stack = self.branch.get_config_stack()
628
 
 
629
 
    def check_append_revisions_only(self, expected_value, value=None):
630
 
        """Set append_revisions_only in config and check its interpretation."""
631
 
        if value is not None:
632
 
            self.config_stack.set('append_revisions_only', value)
633
 
        self.assertEqual(expected_value,
634
 
                         self.branch.get_append_revisions_only())
635
 
 
636
 
    def test_valid_append_revisions_only(self):
637
 
        self.assertEqual(None,
638
 
                          self.config_stack.get('append_revisions_only'))
639
 
        self.check_append_revisions_only(None)
640
 
        self.check_append_revisions_only(False, 'False')
641
 
        self.check_append_revisions_only(True, 'True')
642
 
        # The following values will cause compatibility problems on projects
643
 
        # using older bzr versions (<2.2) but are accepted
644
 
        self.check_append_revisions_only(False, 'false')
645
 
        self.check_append_revisions_only(True, 'true')
646
 
 
647
 
    def test_invalid_append_revisions_only(self):
648
 
        """Ensure warning is noted on invalid settings"""
649
 
        self.warnings = []
650
 
        def warning(*args):
651
 
            self.warnings.append(args[0] % args[1:])
652
 
        self.overrideAttr(trace, 'warning', warning)
653
 
        self.check_append_revisions_only(None, 'not-a-bool')
654
 
        self.assertLength(1, self.warnings)
655
 
        self.assertEqual(
656
 
            'Value "not-a-bool" is not valid for "append_revisions_only"',
657
 
            self.warnings[0])
658
 
 
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
479
 
705
480
class TestPullResult(tests.TestCase):
706
481
 
 
482
    def test_pull_result_to_int(self):
 
483
        # to support old code, the pull result can be used as an int
 
484
        r = _mod_branch.PullResult()
 
485
        r.old_revno = 10
 
486
        r.new_revno = 20
 
487
        # this usage of results is not recommended for new code (because it
 
488
        # doesn't describe very well what happened), but for api stability
 
489
        # it's still supported
 
490
        a = "%d revisions pulled" % r
 
491
        self.assertEqual(a, "10 revisions pulled")
 
492
 
707
493
    def test_report_changed(self):
708
494
        r = _mod_branch.PullResult()
709
495
        r.old_revid = "old-revid"
713
499
        f = StringIO()
714
500
        r.report(f)
715
501
        self.assertEqual("Now on revision 20.\n", f.getvalue())
716
 
        self.assertEqual("Now on revision 20.\n", f.getvalue())
717
502
 
718
503
    def test_report_unchanged(self):
719
504
        r = _mod_branch.PullResult()
721
506
        r.new_revid = "same-revid"
722
507
        f = StringIO()
723
508
        r.report(f)
724
 
        self.assertEqual("No revisions or tags to pull.\n", f.getvalue())
 
509
        self.assertEqual("No revisions to pull.\n", f.getvalue())
 
510
 
 
511
 
 
512
class _StubLockable(object):
 
513
    """Helper for TestRunWithWriteLockedTarget."""
 
514
 
 
515
    def __init__(self, calls, unlock_exc=None):
 
516
        self.calls = calls
 
517
        self.unlock_exc = unlock_exc
 
518
 
 
519
    def lock_write(self):
 
520
        self.calls.append('lock_write')
 
521
 
 
522
    def unlock(self):
 
523
        self.calls.append('unlock')
 
524
        if self.unlock_exc is not None:
 
525
            raise self.unlock_exc
 
526
 
 
527
 
 
528
class _ErrorFromCallable(Exception):
 
529
    """Helper for TestRunWithWriteLockedTarget."""
 
530
 
 
531
 
 
532
class _ErrorFromUnlock(Exception):
 
533
    """Helper for TestRunWithWriteLockedTarget."""
 
534
 
 
535
 
 
536
class TestRunWithWriteLockedTarget(tests.TestCase):
 
537
    """Tests for _run_with_write_locked_target."""
 
538
 
 
539
    def setUp(self):
 
540
        tests.TestCase.setUp(self)
 
541
        self._calls = []
 
542
 
 
543
    def func_that_returns_ok(self):
 
544
        self._calls.append('func called')
 
545
        return 'ok'
 
546
 
 
547
    def func_that_raises(self):
 
548
        self._calls.append('func called')
 
549
        raise _ErrorFromCallable()
 
550
 
 
551
    def test_success_unlocks(self):
 
552
        lockable = _StubLockable(self._calls)
 
553
        result = _mod_branch._run_with_write_locked_target(
 
554
            lockable, self.func_that_returns_ok)
 
555
        self.assertEqual('ok', result)
 
556
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
557
 
 
558
    def test_exception_unlocks_and_propagates(self):
 
559
        lockable = _StubLockable(self._calls)
 
560
        self.assertRaises(_ErrorFromCallable,
 
561
                          _mod_branch._run_with_write_locked_target,
 
562
                          lockable, self.func_that_raises)
 
563
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
564
 
 
565
    def test_callable_succeeds_but_error_during_unlock(self):
 
566
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
567
        self.assertRaises(_ErrorFromUnlock,
 
568
                          _mod_branch._run_with_write_locked_target,
 
569
                          lockable, self.func_that_returns_ok)
 
570
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
571
 
 
572
    def test_error_during_unlock_does_not_mask_original_error(self):
 
573
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
574
        self.assertRaises(_ErrorFromCallable,
 
575
                          _mod_branch._run_with_write_locked_target,
 
576
                          lockable, self.func_that_raises)
 
577
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
578
 
 
579