~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

merge bzr.dev

Show diffs side-by-side

added added

removed removed

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