~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-03-16 14:01:20 UTC
  • mfrom: (3280.2.5 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080316140120-i3yq8yr1l66m11h7
Start 1.4 development

Show diffs side-by-side

added added

removed removed

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