~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-19 13:23:58 UTC
  • mto: This revision was merged to the branch mainline in revision 6386.
  • Revision ID: jelmer@canonical.com-20111219132358-uvs5a6y92gomzacd
Move importing from future until after doc string, otherwise the doc string will disappear.

Show diffs side-by-side

added added

removed removed

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