~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-11-09 17:50:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2988.
  • Revision ID: robertc@robertcollins.net-20071109175031-agaiy6530rvbprmb
Change (without backwards compatibility) the
iter_lines_added_or_present_in_versions VersionedFile API to yield the
text version that each line is being returned from. This is useful for
reconcile in determining what inventories reference what texts.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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
 
16
 
 
17
"""Tests for the Branch facility that are not interface  tests.
 
18
 
 
19
For interface tests see tests/branch_implementations/*.py.
 
20
 
 
21
For concrete class tests see this file, and for meta-branch tests
 
22
also see this file.
 
23
"""
 
24
 
 
25
from StringIO import StringIO
 
26
 
 
27
from bzrlib import (
 
28
    branch as _mod_branch,
 
29
    bzrdir,
 
30
    config,
 
31
    errors,
 
32
    trace,
 
33
    urlutils,
 
34
    )
 
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):
 
57
 
 
58
    def test_default_format(self):
 
59
        # update this if you change the default branch format
 
60
        self.assertIsInstance(BranchFormat.get_default_format(),
 
61
                BzrBranchFormat6)
 
62
 
 
63
    def test_default_format_is_same_as_bzrdir_default(self):
 
64
        # XXX: it might be nice if there was only one place the default was
 
65
        # set, but at the moment that's not true -- mbp 20070814 -- 
 
66
        # https://bugs.launchpad.net/bzr/+bug/132376
 
67
        self.assertEqual(BranchFormat.get_default_format(),
 
68
                BzrDirFormat.get_default_format().get_branch_format())
 
69
 
 
70
    def test_get_set_default_format(self):
 
71
        # set the format and then set it back again
 
72
        old_format = BranchFormat.get_default_format()
 
73
        BranchFormat.set_default_format(SampleBranchFormat())
 
74
        try:
 
75
            # the default branch format is used by the meta dir format
 
76
            # which is not the default bzrdir format at this point
 
77
            dir = BzrDirMetaFormat1().initialize('memory:///')
 
78
            result = dir.create_branch()
 
79
            self.assertEqual(result, 'A branch')
 
80
        finally:
 
81
            BranchFormat.set_default_format(old_format)
 
82
        self.assertEqual(old_format, BranchFormat.get_default_format())
 
83
 
 
84
 
 
85
class TestBranchFormat5(TestCaseWithTransport):
 
86
    """Tests specific to branch format 5"""
 
87
 
 
88
    def test_branch_format_5_uses_lockdir(self):
 
89
        url = self.get_url()
 
90
        bzrdir = BzrDirMetaFormat1().initialize(url)
 
91
        bzrdir.create_repository()
 
92
        branch = bzrdir.create_branch()
 
93
        t = self.get_transport()
 
94
        self.log("branch instance is %r" % branch)
 
95
        self.assert_(isinstance(branch, BzrBranch5))
 
96
        self.assertIsDirectory('.', t)
 
97
        self.assertIsDirectory('.bzr/branch', t)
 
98
        self.assertIsDirectory('.bzr/branch/lock', t)
 
99
        branch.lock_write()
 
100
        try:
 
101
            self.assertIsDirectory('.bzr/branch/lock/held', t)
 
102
        finally:
 
103
            branch.unlock()
 
104
 
 
105
    def test_set_push_location(self):
 
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()
 
118
 
 
119
        branch = self.make_branch('.', format='knit')
 
120
        branch.set_push_location('foo')
 
121
        local_path = urlutils.local_path_from_url(branch.base[:-1])
 
122
        self.assertFileEqual("# comment\n"
 
123
                             "[%s]\n"
 
124
                             "push_location = foo\n"
 
125
                             "push_location:policy = norecurse" % local_path,
 
126
                             fn)
 
127
 
 
128
    # TODO RBC 20051029 test getting a push location from a branch in a
 
129
    # recursive section - that is, it appends the branch name.
 
130
 
 
131
 
 
132
class SampleBranchFormat(BranchFormat):
 
133
    """A sample format
 
134
 
 
135
    this format is initializable, unsupported to aid in testing the 
 
136
    open and open_downlevel routines.
 
137
    """
 
138
 
 
139
    def get_format_string(self):
 
140
        """See BzrBranchFormat.get_format_string()."""
 
141
        return "Sample branch format."
 
142
 
 
143
    def initialize(self, a_bzrdir):
 
144
        """Format 4 branches cannot be created."""
 
145
        t = a_bzrdir.get_branch_transport(self)
 
146
        t.put_bytes('format', self.get_format_string())
 
147
        return 'A branch'
 
148
 
 
149
    def is_supported(self):
 
150
        return False
 
151
 
 
152
    def open(self, transport, _found=False):
 
153
        return "opened branch."
 
154
 
 
155
 
 
156
class TestBzrBranchFormat(TestCaseWithTransport):
 
157
    """Tests for the BzrBranchFormat facility."""
 
158
 
 
159
    def test_find_format(self):
 
160
        # is the right format object found for a branch?
 
161
        # create a branch with a few known format objects.
 
162
        # this is not quite the same as 
 
163
        self.build_tree(["foo/", "bar/"])
 
164
        def check_format(format, url):
 
165
            dir = format._matchingbzrdir.initialize(url)
 
166
            dir.create_repository()
 
167
            format.initialize(dir)
 
168
            found_format = BranchFormat.find_format(dir)
 
169
            self.failUnless(isinstance(found_format, format.__class__))
 
170
        check_format(BzrBranchFormat5(), "bar")
 
171
        
 
172
    def test_find_format_not_branch(self):
 
173
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
174
        self.assertRaises(NotBranchError,
 
175
                          BranchFormat.find_format,
 
176
                          dir)
 
177
 
 
178
    def test_find_format_unknown_format(self):
 
179
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
180
        SampleBranchFormat().initialize(dir)
 
181
        self.assertRaises(UnknownFormatError,
 
182
                          BranchFormat.find_format,
 
183
                          dir)
 
184
 
 
185
    def test_register_unregister_format(self):
 
186
        format = SampleBranchFormat()
 
187
        # make a control dir
 
188
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
189
        # make a branch
 
190
        format.initialize(dir)
 
191
        # register a format for it.
 
192
        BranchFormat.register_format(format)
 
193
        # which branch.Open will refuse (not supported)
 
194
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
 
195
        self.make_branch_and_tree('foo')
 
196
        # but open_downlevel will work
 
197
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
198
        # unregister the format
 
199
        BranchFormat.unregister_format(format)
 
200
        self.make_branch_and_tree('bar')
 
201
 
 
202
 
 
203
class TestBranch6(TestCaseWithTransport):
 
204
 
 
205
    def test_creation(self):
 
206
        format = BzrDirMetaFormat1()
 
207
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
 
208
        branch = self.make_branch('a', format=format)
 
209
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
210
        branch = self.make_branch('b', format='dirstate-tags')
 
211
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
212
        branch = _mod_branch.Branch.open('a')
 
213
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
214
 
 
215
    def test_layout(self):
 
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')
 
219
 
 
220
    def test_config(self):
 
221
        """Ensure that all configuration data is stored in the branch"""
 
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')
 
227
        config = branch.get_config()._get_branch_data_config()
 
228
        self.assertEqual('sftp://bazaar-vcs.org',
 
229
                         config.get_user_option('push_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())
 
233
 
 
234
    def test_set_revision_history(self):
 
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()
 
248
 
 
249
    def do_checkout_test(self, lightweight=False):
 
250
        tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
 
251
        subtree = self.make_branch_and_tree('source/subtree',
 
252
            format='dirstate-with-subtree')
 
253
        subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
 
254
            format='dirstate-with-subtree')
 
255
        self.build_tree(['source/subtree/file',
 
256
                         'source/subtree/subsubtree/file'])
 
257
        subsubtree.add('file')
 
258
        subtree.add('file')
 
259
        subtree.add_reference(subsubtree)
 
260
        tree.add_reference(subtree)
 
261
        tree.commit('a revision')
 
262
        subtree.commit('a subtree file')
 
263
        subsubtree.commit('a subsubtree file')
 
264
        tree.branch.create_checkout('target', lightweight=lightweight)
 
265
        self.failUnlessExists('target')
 
266
        self.failUnlessExists('target/subtree')
 
267
        self.failUnlessExists('target/subtree/file')
 
268
        self.failUnlessExists('target/subtree/subsubtree/file')
 
269
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
 
270
        if lightweight:
 
271
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
 
272
        else:
 
273
            self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
 
274
 
 
275
    def test_checkout_with_references(self):
 
276
        self.do_checkout_test()
 
277
 
 
278
    def test_light_checkout_with_references(self):
 
279
        self.do_checkout_test(lightweight=True)
 
280
 
 
281
    def test_set_push(self):
 
282
        branch = self.make_branch('source', format='dirstate-tags')
 
283
        branch.get_config().set_user_option('push_location', 'old',
 
284
            store=config.STORE_LOCATION)
 
285
        warnings = []
 
286
        def warning(*args):
 
287
            warnings.append(args[0] % args[1:])
 
288
        _warning = trace.warning
 
289
        trace.warning = warning
 
290
        try:
 
291
            branch.set_push_location('new')
 
292
        finally:
 
293
            trace.warning = _warning
 
294
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
 
295
                         'locations.conf')
 
296
 
 
297
class TestBranchReference(TestCaseWithTransport):
 
298
    """Tests for the branch reference facility."""
 
299
 
 
300
    def test_create_open_reference(self):
 
301
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
 
302
        t = get_transport(self.get_url('.'))
 
303
        t.mkdir('repo')
 
304
        dir = bzrdirformat.initialize(self.get_url('repo'))
 
305
        dir.create_repository()
 
306
        target_branch = dir.create_branch()
 
307
        t.mkdir('branch')
 
308
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
 
309
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
 
310
        self.assertEqual(made_branch.base, target_branch.base)
 
311
        opened_branch = branch_dir.open_branch()
 
312
        self.assertEqual(opened_branch.base, target_branch.base)
 
313
 
 
314
    def test_get_reference(self):
 
315
        """For a BranchReference, get_reference should reutrn the location."""
 
316
        branch = self.make_branch('target')
 
317
        checkout = branch.create_checkout('checkout', lightweight=True)
 
318
        reference_url = branch.bzrdir.root_transport.abspath('') + '/'
 
319
        # if the api for create_checkout changes to return different checkout types
 
320
        # then this file read will fail.
 
321
        self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
 
322
        self.assertEqual(reference_url,
 
323
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
 
324
 
 
325
 
 
326
class TestHooks(TestCase):
 
327
 
 
328
    def test_constructor(self):
 
329
        """Check that creating a BranchHooks instance has the right defaults."""
 
330
        hooks = BranchHooks()
 
331
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
 
332
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
 
333
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
 
334
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
 
335
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
 
336
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
 
337
 
 
338
    def test_installed_hooks_are_BranchHooks(self):
 
339
        """The installed hooks object should be a BranchHooks."""
 
340
        # the installed hooks are saved in self._preserved_hooks.
 
341
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
 
342
 
 
343
 
 
344
class TestPullResult(TestCase):
 
345
 
 
346
    def test_pull_result_to_int(self):
 
347
        # to support old code, the pull result can be used as an int
 
348
        r = PullResult()
 
349
        r.old_revno = 10
 
350
        r.new_revno = 20
 
351
        # this usage of results is not recommended for new code (because it
 
352
        # doesn't describe very well what happened), but for api stability
 
353
        # it's still supported
 
354
        a = "%d revisions pulled" % r
 
355
        self.assertEqual(a, "10 revisions pulled")