~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Robert Collins
  • Date: 2007-10-23 22:14:32 UTC
  • mto: (2592.6.3 repository)
  • mto: This revision was merged to the branch mainline in revision 2967.
  • Revision ID: robertc@robertcollins.net-20071023221432-j8zndh1oiegql3cu
* Commit updates the state of the working tree via a delta rather than
  supplying entirely new basis trees. For commit of a single specified file
  this reduces the wall clock time for commit by roughly a 30%.
  (Robert Collins, Martin Pool)

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
30
    config,
31
31
    errors,
32
 
    symbol_versioning,
33
 
    tests,
34
32
    trace,
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.format_registry.get_default(),
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.format_registry.get_default(),
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.format_registry.get_default()
57
 
        _mod_branch.format_registry.set_default(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.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):
 
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')
94
122
        self.assertFileEqual("# comment\n"
95
123
                             "[%s]\n"
96
124
                             "push_location = foo\n"
97
 
                             "push_location:policy = norecurse\n" % local_path,
98
 
                             config.locations_config_filename())
 
125
                             "push_location:policy = norecurse" % local_path,
 
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, repository=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 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):
 
156
class TestBzrBranchFormat(TestCaseWithTransport):
168
157
    """Tests for the BzrBranchFormat facility."""
169
158
 
170
159
    def test_find_format(self):
171
160
        # is the right format object found for a branch?
172
161
        # create a branch with a few known format objects.
173
 
        # this is not quite the same as
 
162
        # this is not quite the same as 
174
163
        self.build_tree(["foo/", "bar/"])
175
164
        def check_format(format, url):
176
165
            dir = format._matchingbzrdir.initialize(url)
177
166
            dir.create_repository()
178
167
            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
 
 
 
168
            found_format = BranchFormat.find_format(dir)
 
169
            self.failUnless(isinstance(found_format, format.__class__))
 
170
        check_format(BzrBranchFormat5(), "bar")
 
171
        
194
172
    def test_find_format_not_branch(self):
195
173
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
196
 
        self.assertRaises(errors.NotBranchError,
197
 
                          _mod_branch.BranchFormat.find_format,
 
174
        self.assertRaises(NotBranchError,
 
175
                          BranchFormat.find_format,
198
176
                          dir)
199
177
 
200
178
    def test_find_format_unknown_format(self):
201
179
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
202
180
        SampleBranchFormat().initialize(dir)
203
 
        self.assertRaises(errors.UnknownFormatError,
204
 
                          _mod_branch.BranchFormat.find_format,
 
181
        self.assertRaises(UnknownFormatError,
 
182
                          BranchFormat.find_format,
205
183
                          dir)
206
184
 
207
185
    def test_register_unregister_format(self):
208
 
        # Test the deprecated format registration functions
209
186
        format = SampleBranchFormat()
210
187
        # make a control dir
211
188
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
212
189
        # make a branch
213
190
        format.initialize(dir)
214
191
        # register a format for it.
215
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
216
 
            _mod_branch.BranchFormat.register_format, format)
 
192
        BranchFormat.register_format(format)
217
193
        # which branch.Open will refuse (not supported)
218
 
        self.assertRaises(errors.UnsupportedFormatError,
219
 
                          _mod_branch.Branch.open, self.get_url())
 
194
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
220
195
        self.make_branch_and_tree('foo')
221
196
        # but open_downlevel will work
222
 
        self.assertEqual(
223
 
            format.open(dir),
224
 
            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))
225
198
        # unregister the format
226
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
227
 
            _mod_branch.BranchFormat.unregister_format, format)
 
199
        BranchFormat.unregister_format(format)
228
200
        self.make_branch_and_tree('bar')
229
201
 
230
202
 
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)
 
203
class TestBranch6(TestCaseWithTransport):
312
204
 
313
205
    def test_creation(self):
314
 
        format = bzrdir.BzrDirMetaFormat1()
 
206
        format = BzrDirMetaFormat1()
315
207
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
316
208
        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())
 
209
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
210
        branch = self.make_branch('b', format='dirstate-tags')
 
211
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
320
212
        branch = _mod_branch.Branch.open('a')
321
 
        self.assertIsInstance(branch, self.get_class())
 
213
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
322
214
 
323
215
    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')
 
216
        branch = self.make_branch('a', format='dirstate-tags')
 
217
        self.failUnlessExists('a/.bzr/branch/last-revision')
 
218
        self.failIfExists('a/.bzr/branch/revision-history')
328
219
 
329
220
    def test_config(self):
330
221
        """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')
 
222
        branch = self.make_branch('a', format='dirstate-tags')
 
223
        branch.set_parent('http://bazaar-vcs.org')
 
224
        self.failIfExists('a/.bzr/branch/parent')
 
225
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
 
226
        branch.set_push_location('sftp://bazaar-vcs.org')
336
227
        config = branch.get_config()._get_branch_data_config()
337
 
        self.assertEqual('sftp://example.com',
 
228
        self.assertEqual('sftp://bazaar-vcs.org',
338
229
                         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())
 
230
        branch.set_bound_location('ftp://bazaar-vcs.org')
 
231
        self.failIfExists('a/.bzr/branch/bound')
 
232
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
342
233
 
343
234
    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'])
 
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()
359
248
 
360
249
    def do_checkout_test(self, lightweight=False):
361
 
        tree = self.make_branch_and_tree('source',
362
 
            format=self.get_format_name_subtree())
 
250
        tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
363
251
        subtree = self.make_branch_and_tree('source/subtree',
364
 
            format=self.get_format_name_subtree())
 
252
            format='dirstate-with-subtree')
365
253
        subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
366
 
            format=self.get_format_name_subtree())
 
254
            format='dirstate-with-subtree')
367
255
        self.build_tree(['source/subtree/file',
368
256
                         'source/subtree/subsubtree/file'])
369
257
        subsubtree.add('file')
374
262
        subtree.commit('a subtree file')
375
263
        subsubtree.commit('a subsubtree file')
376
264
        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')
 
265
        self.failUnlessExists('target')
 
266
        self.failUnlessExists('target/subtree')
 
267
        self.failUnlessExists('target/subtree/file')
 
268
        self.failUnlessExists('target/subtree/subsubtree/file')
381
269
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
382
270
        if lightweight:
383
271
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
391
279
        self.do_checkout_test(lightweight=True)
392
280
 
393
281
    def test_set_push(self):
394
 
        branch = self.make_branch('source', format=self.get_format_name())
 
282
        branch = self.make_branch('source', format='dirstate-tags')
395
283
        branch.get_config().set_user_option('push_location', 'old',
396
284
            store=config.STORE_LOCATION)
397
285
        warnings = []
406
294
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
407
295
                         'locations.conf')
408
296
 
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):
 
297
class TestBranchReference(TestCaseWithTransport):
544
298
    """Tests for the branch reference facility."""
545
299
 
546
300
    def test_create_open_reference(self):
547
301
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
548
 
        t = self.get_transport()
 
302
        t = get_transport(self.get_url('.'))
549
303
        t.mkdir('repo')
550
304
        dir = bzrdirformat.initialize(self.get_url('repo'))
551
305
        dir.create_repository()
552
306
        target_branch = dir.create_branch()
553
307
        t.mkdir('branch')
554
308
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
555
 
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
556
 
            branch_dir, target_branch=target_branch)
 
309
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
557
310
        self.assertEqual(made_branch.base, target_branch.base)
558
311
        opened_branch = branch_dir.open_branch()
559
312
        self.assertEqual(opened_branch.base, target_branch.base)
570
323
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
571
324
 
572
325
 
573
 
class TestHooks(tests.TestCaseWithTransport):
 
326
class TestHooks(TestCase):
574
327
 
575
328
    def test_constructor(self):
576
329
        """Check that creating a BranchHooks instance has the right defaults."""
577
 
        hooks = _mod_branch.BranchHooks()
 
330
        hooks = BranchHooks()
578
331
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
579
332
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
580
333
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
581
334
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
582
335
        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)
 
336
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
591
337
 
592
338
    def test_installed_hooks_are_BranchHooks(self):
593
339
        """The installed hooks object should be a BranchHooks."""
594
340
        # 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):
 
341
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
 
342
 
 
343
 
 
344
class TestPullResult(TestCase):
682
345
 
683
346
    def test_pull_result_to_int(self):
684
347
        # to support old code, the pull result can be used as an int
685
 
        r = _mod_branch.PullResult()
 
348
        r = PullResult()
686
349
        r.old_revno = 10
687
350
        r.new_revno = 20
688
351
        # this usage of results is not recommended for new code (because it
689
352
        # doesn't describe very well what happened), but for api stability
690
353
        # 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
 
 
714
 
 
715
 
class _StubLockable(object):
716
 
    """Helper for TestRunWithWriteLockedTarget."""
717
 
 
718
 
    def __init__(self, calls, unlock_exc=None):
719
 
        self.calls = calls
720
 
        self.unlock_exc = unlock_exc
721
 
 
722
 
    def lock_write(self):
723
 
        self.calls.append('lock_write')
724
 
 
725
 
    def unlock(self):
726
 
        self.calls.append('unlock')
727
 
        if self.unlock_exc is not None:
728
 
            raise self.unlock_exc
729
 
 
730
 
 
731
 
class _ErrorFromCallable(Exception):
732
 
    """Helper for TestRunWithWriteLockedTarget."""
733
 
 
734
 
 
735
 
class _ErrorFromUnlock(Exception):
736
 
    """Helper for TestRunWithWriteLockedTarget."""
737
 
 
738
 
 
739
 
class TestRunWithWriteLockedTarget(tests.TestCase):
740
 
    """Tests for _run_with_write_locked_target."""
741
 
 
742
 
    def setUp(self):
743
 
        tests.TestCase.setUp(self)
744
 
        self._calls = []
745
 
 
746
 
    def func_that_returns_ok(self):
747
 
        self._calls.append('func called')
748
 
        return 'ok'
749
 
 
750
 
    def func_that_raises(self):
751
 
        self._calls.append('func called')
752
 
        raise _ErrorFromCallable()
753
 
 
754
 
    def test_success_unlocks(self):
755
 
        lockable = _StubLockable(self._calls)
756
 
        result = _mod_branch._run_with_write_locked_target(
757
 
            lockable, self.func_that_returns_ok)
758
 
        self.assertEqual('ok', result)
759
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
760
 
 
761
 
    def test_exception_unlocks_and_propagates(self):
762
 
        lockable = _StubLockable(self._calls)
763
 
        self.assertRaises(_ErrorFromCallable,
764
 
                          _mod_branch._run_with_write_locked_target,
765
 
                          lockable, self.func_that_raises)
766
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
767
 
 
768
 
    def test_callable_succeeds_but_error_during_unlock(self):
769
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
770
 
        self.assertRaises(_ErrorFromUnlock,
771
 
                          _mod_branch._run_with_write_locked_target,
772
 
                          lockable, self.func_that_returns_ok)
773
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
774
 
 
775
 
    def test_error_during_unlock_does_not_mask_original_error(self):
776
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
777
 
        self.assertRaises(_ErrorFromCallable,
778
 
                          _mod_branch._run_with_write_locked_target,
779
 
                          lockable, self.func_that_raises)
780
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
354
        a = "%d revisions pulled" % r
 
355
        self.assertEqual(a, "10 revisions pulled")