~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testbranch.py

  • Committer: Martin Pool
  • Date: 2005-09-15 08:37:41 UTC
  • Revision ID: mbp@sourcefrog.net-20050915083741-70d7550b97c7b580
- some updates for fetch/update function

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
2
 
#
 
1
# (C) 2005 Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
16
 
 
17
 
"""Tests for branch implementations - tests a branch format."""
18
 
 
19
 
from bzrlib import (
20
 
    branch as _mod_branch,
21
 
    bzrdir,
22
 
    config,
23
 
    delta as _mod_delta,
24
 
    errors,
25
 
    gpg,
26
 
    merge,
27
 
    urlutils,
28
 
    transport,
29
 
    remote,
30
 
    repository,
31
 
    revision,
32
 
    symbol_versioning,
33
 
    tests,
34
 
    )
35
 
from bzrlib.tests import (
36
 
    per_branch,
37
 
    )
38
 
from bzrlib.tests.http_server import HttpServer
39
 
from bzrlib.transport import memory
40
 
 
41
 
 
42
 
class TestTestCaseWithBranch(per_branch.TestCaseWithBranch):
43
 
 
44
 
    def test_branch_format_matches_bzrdir_branch_format(self):
45
 
        bzrdir_branch_format = self.bzrdir_format.get_branch_format()
46
 
        self.assertIs(self.branch_format.__class__,
47
 
                      bzrdir_branch_format.__class__)
48
 
 
49
 
    def test_make_branch_gets_expected_format(self):
50
 
        branch = self.make_branch('.')
51
 
        self.assertIs(self.branch_format.__class__,
52
 
            branch._format.__class__)
53
 
 
54
 
 
55
 
class TestBranch(per_branch.TestCaseWithBranch):
56
 
 
57
 
    def test_create_tree_with_merge(self):
58
 
        tree = self.create_tree_with_merge()
59
 
        tree.lock_read()
60
 
        self.addCleanup(tree.unlock)
61
 
        graph = tree.branch.repository.get_graph()
62
 
        ancestry_graph = graph.get_parent_map(
63
 
            tree.branch.repository.all_revision_ids())
64
 
        self.assertEqual({'rev-1':('null:',),
65
 
                          'rev-2':('rev-1', ),
66
 
                          'rev-1.1.1':('rev-1', ),
67
 
                          'rev-3':('rev-2', 'rev-1.1.1', ),
68
 
                         }, ancestry_graph)
69
 
 
70
 
    def test_revision_ids_are_utf8(self):
71
 
        wt = self.make_branch_and_tree('tree')
72
 
        wt.commit('f', rev_id='rev1')
73
 
        wt.commit('f', rev_id='rev2')
74
 
        wt.commit('f', rev_id='rev3')
75
 
 
76
 
        br = self.get_branch()
77
 
        br.fetch(wt.branch)
78
 
        br.generate_revision_history('rev3')
79
 
        rh = br.revision_history()
80
 
        self.assertEqual(['rev1', 'rev2', 'rev3'], rh)
81
 
        for revision_id in rh:
82
 
            self.assertIsInstance(revision_id, str)
83
 
        last = br.last_revision()
84
 
        self.assertEqual('rev3', last)
85
 
        self.assertIsInstance(last, str)
86
 
        revno, last = br.last_revision_info()
87
 
        self.assertEqual(3, revno)
88
 
        self.assertEqual('rev3', last)
89
 
        self.assertIsInstance(last, str)
90
 
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
import os
 
19
 
 
20
from bzrlib.selftest import TestCaseInTempDir
 
21
from bzrlib.branch import Branch
 
22
from bzrlib.trace import mutter
 
23
 
 
24
 
 
25
class TestAppendRevisions(TestCaseInTempDir):
 
26
    """Test appending more than one revision"""
 
27
    def test_append_revisions(self):
 
28
        from bzrlib.branch import Branch
 
29
        br = Branch(".", init=True)
 
30
        br.append_revision("rev1")
 
31
        self.assertEquals(br.revision_history(), ["rev1",])
 
32
        br.append_revision("rev2", "rev3")
 
33
        self.assertEquals(br.revision_history(), ["rev1", "rev2", "rev3"])
 
34
 
 
35
 
 
36
 
 
37
class TestFetch(TestCaseInTempDir):
91
38
    def test_fetch_revisions(self):
92
39
        """Test fetch-revision operation."""
93
 
        wt = self.make_branch_and_tree('b1')
94
 
        b1 = wt.branch
95
 
        self.build_tree_contents([('b1/foo', 'hello')])
96
 
        wt.add(['foo'], ['foo-id'])
97
 
        wt.commit('lala!', rev_id='revision-1', allow_pointless=False)
98
 
 
99
 
        b2 = self.make_branch('b2')
100
 
        b2.fetch(b1)
101
 
 
102
 
        rev = b2.repository.get_revision('revision-1')
103
 
        tree = b2.repository.revision_tree('revision-1')
104
 
        tree.lock_read()
105
 
        self.addCleanup(tree.unlock)
106
 
        self.assertEqual(tree.get_file_text('foo-id'), 'hello')
107
 
 
108
 
    def test_get_revision_delta(self):
109
 
        tree_a = self.make_branch_and_tree('a')
110
 
        self.build_tree(['a/foo'])
111
 
        tree_a.add('foo', 'file1')
112
 
        tree_a.commit('rev1', rev_id='rev1')
113
 
        self.build_tree(['a/vla'])
114
 
        tree_a.add('vla', 'file2')
115
 
        tree_a.commit('rev2', rev_id='rev2')
116
 
 
117
 
        delta = tree_a.branch.get_revision_delta(1)
118
 
        self.assertIsInstance(delta, _mod_delta.TreeDelta)
119
 
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
120
 
        delta = tree_a.branch.get_revision_delta(2)
121
 
        self.assertIsInstance(delta, _mod_delta.TreeDelta)
122
 
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
123
 
 
124
 
    def get_unbalanced_tree_pair(self):
125
 
        """Return two branches, a and b, with one file in a."""
126
 
        tree_a = self.make_branch_and_tree('a')
127
 
        self.build_tree_contents([('a/b', 'b')])
128
 
        tree_a.add('b')
129
 
        tree_a.commit("silly commit", rev_id='A')
130
 
 
131
 
        tree_b = self.make_branch_and_tree('b')
132
 
        return tree_a, tree_b
133
 
 
134
 
    def get_balanced_branch_pair(self):
135
 
        """Returns br_a, br_b as with one commit in a, and b has a's stores."""
136
 
        tree_a, tree_b = self.get_unbalanced_tree_pair()
137
 
        tree_b.branch.repository.fetch(tree_a.branch.repository)
138
 
        return tree_a, tree_b
139
 
 
140
 
    def test_clone_partial(self):
141
 
        """Copy only part of the history of a branch."""
142
 
        # TODO: RBC 20060208 test with a revision not on revision-history.
143
 
        #       what should that behaviour be ? Emailed the list.
144
 
        # First, make a branch with two commits.
145
 
        wt_a = self.make_branch_and_tree('a')
146
 
        self.build_tree(['a/one'])
147
 
        wt_a.add(['one'])
148
 
        wt_a.commit('commit one', rev_id='1')
149
 
        self.build_tree(['a/two'])
150
 
        wt_a.add(['two'])
151
 
        wt_a.commit('commit two', rev_id='2')
152
 
        # Now make a copy of the repository.
153
 
        repo_b = self.make_repository('b')
154
 
        wt_a.branch.repository.copy_content_into(repo_b)
155
 
        # wt_a might be a lightweight checkout, so get a hold of the actual
156
 
        # branch (because you can't do a partial clone of a lightweight
157
 
        # checkout).
158
 
        branch = wt_a.branch.bzrdir.open_branch()
159
 
        # Then make a branch where the new repository is, but specify a revision
160
 
        # ID.  The new branch's history will stop at the specified revision.
161
 
        br_b = branch.clone(repo_b.bzrdir, revision_id='1')
162
 
        self.assertEqual('1', br_b.last_revision())
163
 
 
164
 
    def get_parented_branch(self):
165
 
        wt_a = self.make_branch_and_tree('a')
166
 
        self.build_tree(['a/one'])
167
 
        wt_a.add(['one'])
168
 
        wt_a.commit('commit one', rev_id='1')
169
 
 
170
 
        branch_b = wt_a.branch.bzrdir.sprout('b', revision_id='1').open_branch()
171
 
        self.assertEqual(wt_a.branch.base, branch_b.get_parent())
172
 
        return branch_b
173
 
 
174
 
    def test_clone_branch_nickname(self):
175
 
        # test the nick name is preserved always
176
 
        raise tests.TestSkipped('XXX branch cloning is not yet tested.')
177
 
 
178
 
    def test_clone_branch_parent(self):
179
 
        # test the parent is preserved always
180
 
        branch_b = self.get_parented_branch()
181
 
        repo_c = self.make_repository('c')
182
 
        branch_b.repository.copy_content_into(repo_c)
183
 
        branch_c = branch_b.clone(repo_c.bzrdir)
184
 
        self.assertNotEqual(None, branch_c.get_parent())
185
 
        self.assertEqual(branch_b.get_parent(), branch_c.get_parent())
186
 
 
187
 
        # We can also set a specific parent, and it should be honored
188
 
        random_parent = 'http://example.com/path/to/branch'
189
 
        branch_b.set_parent(random_parent)
190
 
        repo_d = self.make_repository('d')
191
 
        branch_b.repository.copy_content_into(repo_d)
192
 
        branch_d = branch_b.clone(repo_d.bzrdir)
193
 
        self.assertEqual(random_parent, branch_d.get_parent())
194
 
 
195
 
    def test_submit_branch(self):
196
 
        """Submit location can be queried and set"""
197
 
        branch = self.make_branch('branch')
198
 
        self.assertEqual(branch.get_submit_branch(), None)
199
 
        branch.set_submit_branch('sftp://example.com')
200
 
        self.assertEqual(branch.get_submit_branch(), 'sftp://example.com')
201
 
        branch.set_submit_branch('sftp://example.net')
202
 
        self.assertEqual(branch.get_submit_branch(), 'sftp://example.net')
203
 
 
204
 
    def test_public_branch(self):
205
 
        """public location can be queried and set"""
206
 
        branch = self.make_branch('branch')
207
 
        self.assertEqual(branch.get_public_branch(), None)
208
 
        branch.set_public_branch('sftp://example.com')
209
 
        self.assertEqual(branch.get_public_branch(), 'sftp://example.com')
210
 
        branch.set_public_branch('sftp://example.net')
211
 
        self.assertEqual(branch.get_public_branch(), 'sftp://example.net')
212
 
        branch.set_public_branch(None)
213
 
        self.assertEqual(branch.get_public_branch(), None)
214
 
 
215
 
    def test_record_initial_ghost(self):
216
 
        """Branches should support having ghosts."""
217
 
        wt = self.make_branch_and_tree('.')
218
 
        wt.set_parent_ids(['non:existent@rev--ision--0--2'],
219
 
            allow_leftmost_as_ghost=True)
220
 
        self.assertEqual(['non:existent@rev--ision--0--2'],
221
 
            wt.get_parent_ids())
222
 
        rev_id = wt.commit('commit against a ghost first parent.')
223
 
        rev = wt.branch.repository.get_revision(rev_id)
224
 
        self.assertEqual(rev.parent_ids, ['non:existent@rev--ision--0--2'])
225
 
        # parent_sha1s is not populated now, WTF. rbc 20051003
226
 
        self.assertEqual(len(rev.parent_sha1s), 0)
227
 
 
228
 
    def test_record_two_ghosts(self):
229
 
        """Recording with all ghosts works."""
230
 
        wt = self.make_branch_and_tree('.')
231
 
        wt.set_parent_ids([
232
 
                'foo@azkhazan-123123-abcabc',
233
 
                'wibble@fofof--20050401--1928390812',
234
 
            ],
235
 
            allow_leftmost_as_ghost=True)
236
 
        rev_id = wt.commit("commit from ghost base with one merge")
237
 
        # the revision should have been committed with two parents
238
 
        rev = wt.branch.repository.get_revision(rev_id)
239
 
        self.assertEqual(['foo@azkhazan-123123-abcabc',
240
 
            'wibble@fofof--20050401--1928390812'],
241
 
            rev.parent_ids)
242
 
 
243
 
    def test_bad_revision(self):
244
 
        self.assertRaises(errors.InvalidRevisionId,
245
 
                          self.get_branch().repository.get_revision,
246
 
                          None)
247
 
 
248
 
# TODO 20051003 RBC:
249
 
# compare the gpg-to-sign info for a commit with a ghost and
250
 
#     an identical tree without a ghost
251
 
# fetch missing should rewrite the TOC of weaves to list newly available parents.
252
 
 
253
 
    def test_sign_existing_revision(self):
254
 
        wt = self.make_branch_and_tree('.')
255
 
        branch = wt.branch
256
 
        wt.commit("base", allow_pointless=True, rev_id='A')
257
 
        from bzrlib.testament import Testament
258
 
        strategy = gpg.LoopbackGPGStrategy(None)
259
 
        branch.repository.lock_write()
260
 
        branch.repository.start_write_group()
261
 
        branch.repository.sign_revision('A', strategy)
262
 
        branch.repository.commit_write_group()
263
 
        branch.repository.unlock()
264
 
        self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
265
 
                         Testament.from_revision(branch.repository,
266
 
                         'A').as_short_text() +
267
 
                         '-----END PSEUDO-SIGNED CONTENT-----\n',
268
 
                         branch.repository.get_signature_text('A'))
269
 
 
270
 
    def test_store_signature(self):
271
 
        wt = self.make_branch_and_tree('.')
272
 
        branch = wt.branch
273
 
        branch.lock_write()
274
 
        try:
275
 
            branch.repository.start_write_group()
276
 
            try:
277
 
                branch.repository.store_revision_signature(
278
 
                    gpg.LoopbackGPGStrategy(None), 'FOO', 'A')
279
 
            except:
280
 
                branch.repository.abort_write_group()
281
 
                raise
282
 
            else:
283
 
                branch.repository.commit_write_group()
284
 
        finally:
285
 
            branch.unlock()
286
 
        # A signature without a revision should not be accessible.
287
 
        self.assertRaises(errors.NoSuchRevision,
288
 
                          branch.repository.has_signature_for_revision_id,
289
 
                          'A')
290
 
        wt.commit("base", allow_pointless=True, rev_id='A')
291
 
        self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n'
292
 
                         'FOO-----END PSEUDO-SIGNED CONTENT-----\n',
293
 
                         branch.repository.get_signature_text('A'))
294
 
 
295
 
    def test_branch_keeps_signatures(self):
296
 
        wt = self.make_branch_and_tree('source')
297
 
        wt.commit('A', allow_pointless=True, rev_id='A')
298
 
        repo = wt.branch.repository
299
 
        repo.lock_write()
300
 
        repo.start_write_group()
301
 
        repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
302
 
        repo.commit_write_group()
303
 
        repo.unlock()
304
 
        #FIXME: clone should work to urls,
305
 
        # wt.clone should work to disks.
306
 
        self.build_tree(['target/'])
307
 
        d2 = repo.bzrdir.clone(urlutils.local_path_to_url('target'))
308
 
        self.assertEqual(repo.get_signature_text('A'),
309
 
                         d2.open_repository().get_signature_text('A'))
310
 
 
311
 
    def test_nicks(self):
312
 
        """Test explicit and implicit branch nicknames.
313
 
 
314
 
        Nicknames are implicitly the name of the branch's directory, unless an
315
 
        explicit nickname is set.  That is, an explicit nickname always
316
 
        overrides the implicit one.
317
 
        """
318
 
        t = self.get_transport()
319
 
        branch = self.make_branch('bzr.dev')
320
 
        # The nick will be 'bzr.dev', because there is no explicit nick set.
321
 
        self.assertEqual(branch.nick, 'bzr.dev')
322
 
        # Move the branch to a different directory, 'bzr.ab'.  Now that branch
323
 
        # will report its nick as 'bzr.ab'.
324
 
        t.move('bzr.dev', 'bzr.ab')
325
 
        branch = _mod_branch.Branch.open(self.get_url('bzr.ab'))
326
 
        self.assertEqual(branch.nick, 'bzr.ab')
327
 
        # Set the branch nick explicitly.  This will ensure there's a branch
328
 
        # config file in the branch.
329
 
        branch.nick = "Aaron's branch"
330
 
        if not isinstance(branch, remote.RemoteBranch):
331
 
            self.assertTrue(branch._transport.has("branch.conf"))
332
 
        # Because the nick has been set explicitly, the nick is now always
333
 
        # "Aaron's branch", regardless of directory name.
334
 
        self.assertEqual(branch.nick, "Aaron's branch")
335
 
        t.move('bzr.ab', 'integration')
336
 
        branch = _mod_branch.Branch.open(self.get_url('integration'))
337
 
        self.assertEqual(branch.nick, "Aaron's branch")
338
 
        branch.nick = u"\u1234"
339
 
        self.assertEqual(branch.nick, u"\u1234")
340
 
 
341
 
    def test_commit_nicks(self):
342
 
        """Nicknames are committed to the revision"""
343
 
        wt = self.make_branch_and_tree('bzr.dev')
344
 
        branch = wt.branch
345
 
        branch.nick = "My happy branch"
346
 
        wt.commit('My commit respect da nick.')
347
 
        committed = branch.repository.get_revision(branch.last_revision())
348
 
        self.assertEqual(committed.properties["branch-nick"],
349
 
                         "My happy branch")
350
 
 
351
 
    def test_create_colocated(self):
352
 
        try:
353
 
            repo = self.make_repository('.', shared=True)
354
 
        except errors.IncompatibleFormat:
355
 
            return
356
 
        self.assertEquals(0, len(repo.bzrdir.list_branches()))
357
 
        try:
358
 
            child_branch1 = self.branch_format.initialize(repo.bzrdir, 
359
 
                name='branch1')
360
 
        except (errors.UninitializableFormat, errors.NoColocatedBranchSupport):
361
 
            # branch references are not default init'able and
362
 
            # not all bzrdirs support colocated branches.
363
 
            return
364
 
        self.assertEquals(1, len(repo.bzrdir.list_branches()))
365
 
        self.branch_format.initialize(repo.bzrdir, name='branch2')
366
 
        self.assertEquals(2, len(repo.bzrdir.list_branches()))
367
 
 
368
 
    def test_create_append_revisions_only(self):
369
 
        try:
370
 
            repo = self.make_repository('.', shared=True)
371
 
        except errors.IncompatibleFormat:
372
 
            return
373
 
        for val in (True, False):
374
 
            try:
375
 
                branch = self.branch_format.initialize(repo.bzrdir,
376
 
                    append_revisions_only=True)
377
 
            except (errors.UninitializableFormat, errors.UpgradeRequired):
378
 
                # branch references are not default init'able and
379
 
                # not all branches support append_revisions_only
380
 
                return
381
 
            self.assertEquals(True, branch.get_append_revisions_only())
382
 
            repo.bzrdir.destroy_branch()
383
 
 
384
 
    def test_get_set_append_revisions_only(self):
385
 
        branch = self.make_branch('.')
386
 
        if branch._format.supports_set_append_revisions_only():
387
 
            branch.set_append_revisions_only(True)
388
 
            self.assertTrue(branch.get_append_revisions_only())
389
 
            branch.set_append_revisions_only(False)
390
 
            self.assertFalse(branch.get_append_revisions_only())
391
 
        else:
392
 
            self.assertRaises(errors.UpgradeRequired,
393
 
                branch.set_append_revisions_only, True)
394
 
            self.assertFalse(branch.get_append_revisions_only())
395
 
 
396
 
    def test_create_open_branch_uses_repository(self):
397
 
        try:
398
 
            repo = self.make_repository('.', shared=True)
399
 
        except errors.IncompatibleFormat:
400
 
            return
401
 
        child_transport = repo.bzrdir.root_transport.clone('child')
402
 
        child_transport.mkdir('.')
403
 
        child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
404
 
        try:
405
 
            child_branch = self.branch_format.initialize(child_dir)
406
 
        except errors.UninitializableFormat:
407
 
            # branch references are not default init'able.
408
 
            return
409
 
        self.assertEqual(repo.bzrdir.root_transport.base,
410
 
                         child_branch.repository.bzrdir.root_transport.base)
411
 
        child_branch = _mod_branch.Branch.open(self.get_url('child'))
412
 
        self.assertEqual(repo.bzrdir.root_transport.base,
413
 
                         child_branch.repository.bzrdir.root_transport.base)
414
 
 
415
 
    def test_format_description(self):
416
 
        tree = self.make_branch_and_tree('tree')
417
 
        text = tree.branch._format.get_format_description()
418
 
        self.assertTrue(len(text))
419
 
 
420
 
    def test_get_commit_builder(self):
421
 
        branch = self.make_branch(".")
422
 
        branch.lock_write()
423
 
        builder = branch.get_commit_builder([])
424
 
        self.assertIsInstance(builder, repository.CommitBuilder)
425
 
        branch.repository.commit_write_group()
426
 
        branch.unlock()
427
 
 
428
 
    def test_generate_revision_history(self):
429
 
        """Create a fake revision history easily."""
430
 
        tree = self.make_branch_and_tree('.')
431
 
        rev1 = tree.commit('foo')
432
 
        orig_history = tree.branch.revision_history()
433
 
        rev2 = tree.commit('bar', allow_pointless=True)
434
 
        tree.branch.generate_revision_history(rev1)
435
 
        self.assertEqual(orig_history, tree.branch.revision_history())
436
 
 
437
 
    def test_generate_revision_history_NULL_REVISION(self):
438
 
        tree = self.make_branch_and_tree('.')
439
 
        rev1 = tree.commit('foo')
440
 
        tree.branch.generate_revision_history(revision.NULL_REVISION)
441
 
        self.assertEqual([], tree.branch.revision_history())
442
 
 
443
 
    def test_create_checkout(self):
444
 
        tree_a = self.make_branch_and_tree('a')
445
 
        branch_a = tree_a.branch
446
 
        checkout_b = branch_a.create_checkout('b')
447
 
        self.assertEqual('null:', checkout_b.last_revision())
448
 
        checkout_b.commit('rev1', rev_id='rev1')
449
 
        self.assertEqual('rev1', branch_a.last_revision())
450
 
        self.assertNotEqual(checkout_b.branch.base, branch_a.base)
451
 
 
452
 
        checkout_c = branch_a.create_checkout('c', lightweight=True)
453
 
        self.assertEqual('rev1', checkout_c.last_revision())
454
 
        checkout_c.commit('rev2', rev_id='rev2')
455
 
        self.assertEqual('rev2', branch_a.last_revision())
456
 
        self.assertEqual(checkout_c.branch.base, branch_a.base)
457
 
 
458
 
        checkout_d = branch_a.create_checkout('d', lightweight=True)
459
 
        self.assertEqual('rev2', checkout_d.last_revision())
460
 
        checkout_e = branch_a.create_checkout('e')
461
 
        self.assertEqual('rev2', checkout_e.last_revision())
462
 
 
463
 
    def test_create_anonymous_lightweight_checkout(self):
464
 
        """A lightweight checkout from a readonly branch should succeed."""
465
 
        tree_a = self.make_branch_and_tree('a')
466
 
        rev_id = tree_a.commit('put some content in the branch')
467
 
        # open the branch via a readonly transport
468
 
        source_branch = _mod_branch.Branch.open(self.get_readonly_url('a'))
469
 
        # sanity check that the test will be valid
470
 
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
471
 
            source_branch.lock_write)
472
 
        checkout = source_branch.create_checkout('c', lightweight=True)
473
 
        self.assertEqual(rev_id, checkout.last_revision())
474
 
 
475
 
    def test_create_anonymous_heavyweight_checkout(self):
476
 
        """A regular checkout from a readonly branch should succeed."""
477
 
        tree_a = self.make_branch_and_tree('a')
478
 
        rev_id = tree_a.commit('put some content in the branch')
479
 
        # open the branch via a readonly transport
480
 
        source_branch = _mod_branch.Branch.open(self.get_readonly_url('a'))
481
 
        # sanity check that the test will be valid
482
 
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
483
 
            source_branch.lock_write)
484
 
        checkout = source_branch.create_checkout('c')
485
 
        self.assertEqual(rev_id, checkout.last_revision())
486
 
 
487
 
    def test_set_revision_history(self):
488
 
        tree = self.make_branch_and_tree('a')
489
 
        tree.commit('a commit', rev_id='rev1')
490
 
        br = tree.branch
491
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
492
 
            br.set_revision_history, ["rev1"])
493
 
        self.assertEquals(br.revision_history(), ["rev1"])
494
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
495
 
            br.set_revision_history, [])
496
 
        self.assertEquals(br.revision_history(), [])
497
 
 
498
 
    def test_heads_to_fetch(self):
499
 
        # heads_to_fetch is a method that returns a collection of revids that
500
 
        # need to be fetched to copy this branch into another repo.  At a
501
 
        # minimum this will include the tip.
502
 
        # (In native formats, this is the tip + tags, but other formats may
503
 
        # have other revs needed)
504
 
        tree = self.make_branch_and_tree('a')
505
 
        tree.commit('first commit', rev_id='rev1')
506
 
        tree.commit('second commit', rev_id='rev2')
507
 
        must_fetch, should_fetch = tree.branch.heads_to_fetch()
508
 
        self.assertTrue('rev2' in must_fetch)
509
 
 
510
 
    def test_heads_to_fetch_not_null_revision(self):
511
 
        # NULL_REVISION does not appear in the result of heads_to_fetch, even
512
 
        # for an empty branch.
513
 
        tree = self.make_branch_and_tree('a')
514
 
        must_fetch, should_fetch = tree.branch.heads_to_fetch()
515
 
        self.assertFalse(revision.NULL_REVISION in must_fetch)
516
 
        self.assertFalse(revision.NULL_REVISION in should_fetch)
517
 
 
518
 
 
519
 
class TestBranchFormat(per_branch.TestCaseWithBranch):
520
 
 
521
 
    def test_branch_format_network_name(self):
522
 
        br = self.make_branch('.')
523
 
        format = br._format
524
 
        network_name = format.network_name()
525
 
        self.assertIsInstance(network_name, str)
526
 
        # We want to test that the network_name matches the actual format on
527
 
        # disk. For local branches that means that using network_name as a key
528
 
        # in the registry gives back the same format. For remote branches we
529
 
        # check that the network_name of the RemoteBranchFormat we have locally
530
 
        # matches the actual format present on disk.
531
 
        if isinstance(format, remote.RemoteBranchFormat):
532
 
            br._ensure_real()
533
 
            real_branch = br._real_branch
534
 
            self.assertEqual(real_branch._format.network_name(), network_name)
535
 
        else:
536
 
            registry = _mod_branch.network_format_registry
537
 
            looked_up_format = registry.get(network_name)
538
 
            self.assertEqual(format.__class__, looked_up_format.__class__)
539
 
 
540
 
    def get_get_config_calls(self):
541
 
        # Smoke test that all branch succeed getting a config
542
 
        br = self.make_branch('.')
543
 
        br.get_config()
544
 
        br.get_config_stack()
545
 
 
546
 
 
547
 
class ChrootedTests(per_branch.TestCaseWithBranch):
548
 
    """A support class that provides readonly urls outside the local namespace.
549
 
 
550
 
    This is done by checking if self.transport_server is a MemoryServer. if it
551
 
    is then we are chrooted already, if it is not then an HttpServer is used
552
 
    for readonly urls.
553
 
    """
554
 
 
555
 
    def setUp(self):
556
 
        super(ChrootedTests, self).setUp()
557
 
        if not self.vfs_transport_factory == memory.MemoryServer:
558
 
            self.transport_readonly_server = HttpServer
559
 
 
560
 
    def test_open_containing(self):
561
 
        self.assertRaises(errors.NotBranchError,
562
 
                          _mod_branch.Branch.open_containing,
563
 
                          self.get_readonly_url(''))
564
 
        self.assertRaises(errors.NotBranchError,
565
 
                          _mod_branch.Branch.open_containing,
566
 
                          self.get_readonly_url('g/p/q'))
567
 
        branch = self.make_branch('.')
568
 
        branch, relpath = _mod_branch.Branch.open_containing(
569
 
            self.get_readonly_url(''))
570
 
        self.assertEqual('', relpath)
571
 
        branch, relpath = _mod_branch.Branch.open_containing(
572
 
            self.get_readonly_url('g/p/q'))
573
 
        self.assertEqual('g/p/q', relpath)
574
 
 
575
 
 
576
 
class InstrumentedTransaction(object):
577
 
 
578
 
    def finish(self):
579
 
        self.calls.append('finish')
580
 
 
581
 
    def __init__(self):
582
 
        self.calls = []
583
 
 
584
 
 
585
 
class TestDecorator(object):
586
 
 
587
 
    def __init__(self):
588
 
        self._calls = []
589
 
 
590
 
    def lock_read(self):
591
 
        self._calls.append('lr')
592
 
 
593
 
    def lock_write(self):
594
 
        self._calls.append('lw')
595
 
 
596
 
    def unlock(self):
597
 
        self._calls.append('ul')
598
 
 
599
 
    @_mod_branch.needs_read_lock
600
 
    def do_with_read(self):
601
 
        return 1
602
 
 
603
 
    @_mod_branch.needs_read_lock
604
 
    def except_with_read(self):
605
 
        raise RuntimeError
606
 
 
607
 
    @_mod_branch.needs_write_lock
608
 
    def do_with_write(self):
609
 
        return 2
610
 
 
611
 
    @_mod_branch.needs_write_lock
612
 
    def except_with_write(self):
613
 
        raise RuntimeError
614
 
 
615
 
 
616
 
class TestDecorators(tests.TestCase):
617
 
 
618
 
    def test_needs_read_lock(self):
619
 
        branch = TestDecorator()
620
 
        self.assertEqual(1, branch.do_with_read())
621
 
        self.assertEqual(['lr', 'ul'], branch._calls)
622
 
 
623
 
    def test_excepts_in_read_lock(self):
624
 
        branch = TestDecorator()
625
 
        self.assertRaises(RuntimeError, branch.except_with_read)
626
 
        self.assertEqual(['lr', 'ul'], branch._calls)
627
 
 
628
 
    def test_needs_write_lock(self):
629
 
        branch = TestDecorator()
630
 
        self.assertEqual(2, branch.do_with_write())
631
 
        self.assertEqual(['lw', 'ul'], branch._calls)
632
 
 
633
 
    def test_excepts_in_write_lock(self):
634
 
        branch = TestDecorator()
635
 
        self.assertRaises(RuntimeError, branch.except_with_write)
636
 
        self.assertEqual(['lw', 'ul'], branch._calls)
637
 
 
638
 
 
639
 
class TestBranchPushLocations(per_branch.TestCaseWithBranch):
640
 
 
641
 
    def test_get_push_location_unset(self):
642
 
        self.assertEqual(None, self.get_branch().get_push_location())
643
 
 
644
 
    def test_get_push_location_exact(self):
645
 
        b = self.get_branch()
646
 
        config.LocationConfig.from_string(
647
 
            '[%s]\npush_location=foo\n' % (b.base,), b.base, save=True)
648
 
        self.assertEqual("foo", self.get_branch().get_push_location())
649
 
 
650
 
    def test_set_push_location(self):
651
 
        branch = self.get_branch()
652
 
        branch.set_push_location('foo')
653
 
        self.assertEqual('foo', branch.get_push_location())
654
 
 
655
 
 
656
 
class TestChildSubmitFormats(per_branch.TestCaseWithBranch):
657
 
 
658
 
    def test_get_child_submit_format_default(self):
659
 
        submit_format = self.get_branch().get_child_submit_format()
660
 
        self.assertTrue(submit_format is None or
661
 
                        isinstance(submit_format, str))
662
 
 
663
 
    def test_get_child_submit_format(self):
664
 
        branch = self.get_branch()
665
 
        branch.get_config().set_user_option('child_submit_format', '10')
666
 
        branch = self.get_branch()
667
 
        self.assertEqual('10', branch.get_child_submit_format())
668
 
 
669
 
 
670
 
class TestFormat(per_branch.TestCaseWithBranch):
671
 
    """Tests for the format itself."""
672
 
 
673
 
    def test_get_reference(self):
674
 
        """get_reference on all regular branches should return None."""
675
 
        if not self.branch_format.is_supported():
676
 
            # unsupported formats are not loopback testable
677
 
            # because the default open will not open them and
678
 
            # they may not be initializable.
679
 
            return
680
 
        made_branch = self.make_branch('.')
681
 
        self.assertEqual(None,
682
 
            made_branch._format.get_reference(made_branch.bzrdir))
683
 
 
684
 
    def test_set_reference(self):
685
 
        """set_reference on all regular branches should be callable."""
686
 
        if not self.branch_format.is_supported():
687
 
            # unsupported formats are not loopback testable
688
 
            # because the default open will not open them and
689
 
            # they may not be initializable.
690
 
            return
691
 
        this_branch = self.make_branch('this')
692
 
        other_branch = self.make_branch('other')
693
 
        try:
694
 
            this_branch._format.set_reference(this_branch.bzrdir, None,
695
 
                other_branch)
696
 
        except NotImplementedError:
697
 
            # that's ok
698
 
            pass
699
 
        else:
700
 
            ref = this_branch._format.get_reference(this_branch.bzrdir)
701
 
            self.assertEqual(ref, other_branch.base)
702
 
 
703
 
    def test_format_initialize_find_open(self):
704
 
        # loopback test to check the current format initializes to itself.
705
 
        if not self.branch_format.is_supported():
706
 
            # unsupported formats are not loopback testable
707
 
            # because the default open will not open them and
708
 
            # they may not be initializable.
709
 
            return
710
 
        # supported formats must be able to init and open
711
 
        t = self.get_transport()
712
 
        readonly_t = transport.get_transport_from_url(self.get_readonly_url())
713
 
        made_branch = self.make_branch('.')
714
 
        self.assertIsInstance(made_branch, _mod_branch.Branch)
715
 
 
716
 
        # find it via bzrdir opening:
717
 
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
718
 
        direct_opened_branch = opened_control.open_branch()
719
 
        self.assertEqual(direct_opened_branch.__class__, made_branch.__class__)
720
 
        self.assertEqual(opened_control, direct_opened_branch.bzrdir)
721
 
        self.assertIsInstance(direct_opened_branch._format,
722
 
            self.branch_format.__class__)
723
 
 
724
 
        # find it via Branch.open
725
 
        opened_branch = _mod_branch.Branch.open(readonly_t.base)
726
 
        self.assertIsInstance(opened_branch, made_branch.__class__)
727
 
        self.assertEqual(made_branch._format.__class__,
728
 
                         opened_branch._format.__class__)
729
 
        # if it has a unique id string, can we probe for it ?
730
 
        try:
731
 
            self.branch_format.get_format_string()
732
 
        except NotImplementedError:
733
 
            return
734
 
        self.assertEqual(self.branch_format,
735
 
                         opened_control.find_branch_format())
736
 
 
737
 
 
738
 
class TestBound(per_branch.TestCaseWithBranch):
739
 
 
740
 
    def test_bind_unbind(self):
741
 
        branch = self.make_branch('1')
742
 
        branch2 = self.make_branch('2')
743
 
        try:
744
 
            branch.bind(branch2)
745
 
        except errors.UpgradeRequired:
746
 
            raise tests.TestNotApplicable('Format does not support binding')
747
 
        self.assertTrue(branch.unbind())
748
 
        self.assertFalse(branch.unbind())
749
 
        self.assertIs(None, branch.get_bound_location())
750
 
 
751
 
    def test_old_bound_location(self):
752
 
        branch = self.make_branch('branch1')
753
 
        try:
754
 
            self.assertIs(None, branch.get_old_bound_location())
755
 
        except errors.UpgradeRequired:
756
 
            raise tests.TestNotApplicable(
757
 
                    'Format does not store old bound locations')
758
 
        branch2 = self.make_branch('branch2')
759
 
        branch.bind(branch2)
760
 
        self.assertIs(None, branch.get_old_bound_location())
761
 
        branch.unbind()
762
 
        self.assertContainsRe(branch.get_old_bound_location(), '\/branch2\/$')
763
 
 
764
 
    def test_bind_diverged(self):
765
 
        tree_a = self.make_branch_and_tree('tree_a')
766
 
        tree_a.commit('rev1a')
767
 
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
768
 
        tree_a.commit('rev2a')
769
 
        tree_b.commit('rev2b')
770
 
        try:
771
 
            tree_b.branch.bind(tree_a.branch)
772
 
        except errors.UpgradeRequired:
773
 
            raise tests.TestNotApplicable('Format does not support binding')
774
 
 
775
 
    def test_unbind_clears_cached_master_branch(self):
776
 
        """b.unbind clears any cached value of b.get_master_branch."""
777
 
        master = self.make_branch('master')
778
 
        branch = self.make_branch('branch')
779
 
        try:
780
 
            branch.bind(master)
781
 
        except errors.UpgradeRequired:
782
 
            raise tests.TestNotApplicable('Format does not support binding')
783
 
        self.addCleanup(branch.lock_write().unlock)
784
 
        self.assertNotEqual(None, branch.get_master_branch())
785
 
        branch.unbind()
786
 
        self.assertEqual(None, branch.get_master_branch())
787
 
 
788
 
    def test_unlocked_does_not_cache_master_branch(self):
789
 
        """Unlocked branches do not cache the result of get_master_branch."""
790
 
        master = self.make_branch('master')
791
 
        branch1 = self.make_branch('branch')
792
 
        try:
793
 
            branch1.bind(master)
794
 
        except errors.UpgradeRequired:
795
 
            raise tests.TestNotApplicable('Format does not support binding')
796
 
        # Open branch1 again
797
 
        branch2 = branch1.bzrdir.open_branch()
798
 
        self.assertNotEqual(None, branch1.get_master_branch())
799
 
        # Unbind the branch via branch2.  branch1 isn't locked so will
800
 
        # immediately return the new value for get_master_branch.
801
 
        branch2.unbind()
802
 
        self.assertEqual(None, branch1.get_master_branch())
803
 
 
804
 
    def test_bind_clears_cached_master_branch(self):
805
 
        """b.bind clears any cached value of b.get_master_branch."""
806
 
        master1 = self.make_branch('master1')
807
 
        master2 = self.make_branch('master2')
808
 
        branch = self.make_branch('branch')
809
 
        try:
810
 
            branch.bind(master1)
811
 
        except errors.UpgradeRequired:
812
 
            raise tests.TestNotApplicable('Format does not support binding')
813
 
        self.addCleanup(branch.lock_write().unlock)
814
 
        self.assertNotEqual(None, branch.get_master_branch())
815
 
        branch.bind(master2)
816
 
        self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
817
 
                branch.get_master_branch().base))
818
 
 
819
 
    def test_set_bound_location_clears_cached_master_branch(self):
820
 
        """b.set_bound_location clears any cached value of b.get_master_branch.
821
 
        """
822
 
        master1 = self.make_branch('master1')
823
 
        master2 = self.make_branch('master2')
824
 
        branch = self.make_branch('branch')
825
 
        try:
826
 
            branch.bind(master1)
827
 
        except errors.UpgradeRequired:
828
 
            raise tests.TestNotApplicable('Format does not support binding')
829
 
        self.addCleanup(branch.lock_write().unlock)
830
 
        self.assertNotEqual(None, branch.get_master_branch())
831
 
        branch.set_bound_location(self.get_url('master2'))
832
 
        self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
833
 
                branch.get_master_branch().base))
834
 
 
835
 
 
836
 
class TestStrict(per_branch.TestCaseWithBranch):
837
 
 
838
 
    def test_strict_history(self):
839
 
        tree1 = self.make_branch_and_tree('tree1')
840
 
        try:
841
 
            tree1.branch.set_append_revisions_only(True)
842
 
        except errors.UpgradeRequired:
843
 
            raise tests.TestSkipped('Format does not support strict history')
844
 
        tree1.commit('empty commit')
845
 
        tree2 = tree1.bzrdir.sprout('tree2').open_workingtree()
846
 
        tree2.commit('empty commit 2')
847
 
        tree1.pull(tree2.branch)
848
 
        tree1.commit('empty commit 3')
849
 
        tree2.commit('empty commit 4')
850
 
        self.assertRaises(errors.DivergedBranches, tree1.pull, tree2.branch)
851
 
        tree2.merge_from_branch(tree1.branch)
852
 
        tree2.commit('empty commit 5')
853
 
        self.assertRaises(errors.AppendRevisionsOnlyViolation, tree1.pull,
854
 
                          tree2.branch)
855
 
        tree3 = tree1.bzrdir.sprout('tree3').open_workingtree()
856
 
        tree3.merge_from_branch(tree2.branch)
857
 
        tree3.commit('empty commit 6')
858
 
        tree2.pull(tree3.branch)
859
 
 
860
 
 
861
 
class TestIgnoreFallbacksParameter(per_branch.TestCaseWithBranch):
862
 
 
863
 
    def make_branch_with_fallback(self):
864
 
        fallback = self.make_branch('fallback')
865
 
        if not fallback._format.supports_stacking():
866
 
            raise tests.TestNotApplicable("format does not support stacking")
867
 
        stacked = self.make_branch('stacked')
868
 
        stacked.set_stacked_on_url(fallback.base)
869
 
        return stacked
870
 
 
871
 
    def test_fallbacks_not_opened(self):
872
 
        stacked = self.make_branch_with_fallback()
873
 
        self.get_transport('').rename('fallback', 'moved')
874
 
        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=True)
875
 
        self.assertEqual([], reopened.repository._fallback_repositories)
876
 
 
877
 
    def test_fallbacks_are_opened(self):
878
 
        stacked = self.make_branch_with_fallback()
879
 
        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=False)
880
 
        self.assertLength(1, reopened.repository._fallback_repositories)
881
 
 
882
 
 
883
 
class TestReferenceLocation(per_branch.TestCaseWithBranch):
884
 
 
885
 
    def test_reference_parent(self):
886
 
        tree = self.make_branch_and_tree('tree')
887
 
        subtree = self.make_branch_and_tree('tree/subtree')
888
 
        subtree.set_root_id('subtree-id')
889
 
        try:
890
 
            tree.add_reference(subtree)
891
 
        except errors.UnsupportedOperation:
892
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
893
 
        reference_parent = tree.branch.reference_parent('subtree-id',
894
 
                                                        'subtree')
895
 
        self.assertEqual(subtree.branch.base, reference_parent.base)
896
 
 
897
 
    def test_reference_parent_accepts_possible_transports(self):
898
 
        tree = self.make_branch_and_tree('tree')
899
 
        subtree = self.make_branch_and_tree('tree/subtree')
900
 
        subtree.set_root_id('subtree-id')
901
 
        try:
902
 
            tree.add_reference(subtree)
903
 
        except errors.UnsupportedOperation:
904
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
905
 
        reference_parent = tree.branch.reference_parent('subtree-id',
906
 
            'subtree', possible_transports=[subtree.bzrdir.root_transport])
907
 
 
908
 
    def test_get_reference_info(self):
909
 
        branch = self.make_branch('branch')
910
 
        try:
911
 
            path, loc = branch.get_reference_info('file-id')
912
 
        except errors.UnsupportedOperation:
913
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
914
 
        self.assertIs(None, path)
915
 
        self.assertIs(None, loc)
916
 
 
917
 
    def test_set_reference_info(self):
918
 
        branch = self.make_branch('branch')
919
 
        try:
920
 
            branch.set_reference_info('file-id', 'path/to/location',
921
 
                                      'path/to/file')
922
 
        except errors.UnsupportedOperation:
923
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
924
 
 
925
 
    def test_set_get_reference_info(self):
926
 
        branch = self.make_branch('branch')
927
 
        try:
928
 
            branch.set_reference_info('file-id', 'path/to/file',
929
 
                                      'path/to/location')
930
 
        except errors.UnsupportedOperation:
931
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
932
 
        # Create a new instance to ensure storage is permanent
933
 
        branch = _mod_branch.Branch.open('branch')
934
 
        tree_path, branch_location = branch.get_reference_info('file-id')
935
 
        self.assertEqual('path/to/location', branch_location)
936
 
 
937
 
    def test_set_null_reference_info(self):
938
 
        branch = self.make_branch('branch')
939
 
        try:
940
 
            branch.set_reference_info('file-id', 'path/to/file',
941
 
                                      'path/to/location')
942
 
        except errors.UnsupportedOperation:
943
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
944
 
        branch.set_reference_info('file-id', None, None)
945
 
        tree_path, branch_location = branch.get_reference_info('file-id')
946
 
        self.assertIs(None, tree_path)
947
 
        self.assertIs(None, branch_location)
948
 
 
949
 
    def test_set_null_reference_info_when_null(self):
950
 
        branch = self.make_branch('branch')
951
 
        try:
952
 
            tree_path, branch_location = branch.get_reference_info('file-id')
953
 
        except errors.UnsupportedOperation:
954
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
955
 
        self.assertIs(None, tree_path)
956
 
        self.assertIs(None, branch_location)
957
 
        branch.set_reference_info('file-id', None, None)
958
 
 
959
 
    def test_set_null_requires_two_nones(self):
960
 
        branch = self.make_branch('branch')
961
 
        try:
962
 
            e = self.assertRaises(ValueError, branch.set_reference_info,
963
 
                                  'file-id', 'path', None)
964
 
        except errors.UnsupportedOperation:
965
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
966
 
        self.assertEqual('tree_path must be None when branch_location is'
967
 
                         ' None.', str(e))
968
 
        e = self.assertRaises(ValueError, branch.set_reference_info,
969
 
                              'file-id', None, 'location')
970
 
        self.assertEqual('branch_location must be None when tree_path is'
971
 
                         ' None.', str(e))
972
 
 
973
 
    def make_branch_with_reference(self, location, reference_location,
974
 
                                   file_id='file-id'):
975
 
        branch = self.make_branch(location)
976
 
        try:
977
 
            branch.set_reference_info(file_id, 'path/to/file',
978
 
                                      reference_location)
979
 
        except errors.UnsupportedOperation:
980
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
981
 
        return branch
982
 
 
983
 
    def test_reference_parent_from_reference_info_(self):
984
 
        referenced_branch = self.make_branch('reference_branch')
985
 
        branch = self.make_branch_with_reference('branch',
986
 
                                                 referenced_branch.base)
987
 
        parent = branch.reference_parent('file-id', 'path/to/file')
988
 
        self.assertEqual(parent.base, referenced_branch.base)
989
 
 
990
 
    def test_branch_relative_reference_location(self):
991
 
        branch = self.make_branch('branch')
992
 
        try:
993
 
            branch.set_reference_info('file-id', 'path/to/file',
994
 
            '../reference_branch')
995
 
        except errors.UnsupportedOperation:
996
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
997
 
        referenced_branch = self.make_branch('reference_branch')
998
 
        parent = branch.reference_parent('file-id', 'path/to/file')
999
 
        self.assertEqual(parent.base, referenced_branch.base)
1000
 
 
1001
 
    def test_sprout_copies_reference_location(self):
1002
 
        branch = self.make_branch_with_reference('branch', '../reference')
1003
 
        new_branch = branch.bzrdir.sprout('new-branch').open_branch()
1004
 
        self.assertEqual('../reference',
1005
 
                         new_branch.get_reference_info('file-id')[1])
1006
 
 
1007
 
    def test_clone_copies_reference_location(self):
1008
 
        branch = self.make_branch_with_reference('branch', '../reference')
1009
 
        new_branch = branch.bzrdir.clone('new-branch').open_branch()
1010
 
        self.assertEqual('../reference',
1011
 
                         new_branch.get_reference_info('file-id')[1])
1012
 
 
1013
 
    def test_copied_locations_are_rebased(self):
1014
 
        branch = self.make_branch_with_reference('branch', 'reference')
1015
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1016
 
        self.assertEqual('../reference',
1017
 
                         new_branch.get_reference_info('file-id')[1])
1018
 
 
1019
 
    def test_update_references_retains_old_references(self):
1020
 
        branch = self.make_branch_with_reference('branch', 'reference')
1021
 
        new_branch = self.make_branch_with_reference(
1022
 
            'new_branch', 'reference', 'file-id2')
1023
 
        new_branch.update_references(branch)
1024
 
        self.assertEqual('reference',
1025
 
                         branch.get_reference_info('file-id')[1])
1026
 
 
1027
 
    def test_update_references_retains_known_references(self):
1028
 
        branch = self.make_branch_with_reference('branch', 'reference')
1029
 
        new_branch = self.make_branch_with_reference(
1030
 
            'new_branch', 'reference2')
1031
 
        new_branch.update_references(branch)
1032
 
        self.assertEqual('reference',
1033
 
                         branch.get_reference_info('file-id')[1])
1034
 
 
1035
 
    def test_update_references_skips_known_references(self):
1036
 
        branch = self.make_branch_with_reference('branch', 'reference')
1037
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1038
 
        new_branch.set_reference_info('file-id', '../foo', '../foo')
1039
 
        new_branch.update_references(branch)
1040
 
        self.assertEqual('reference',
1041
 
                         branch.get_reference_info('file-id')[1])
1042
 
 
1043
 
    def test_pull_updates_references(self):
1044
 
        branch = self.make_branch_with_reference('branch', 'reference')
1045
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1046
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
1047
 
        branch.pull(new_branch)
1048
 
        self.assertEqual('foo',
1049
 
                         branch.get_reference_info('file-id2')[1])
1050
 
 
1051
 
    def test_push_updates_references(self):
1052
 
        branch = self.make_branch_with_reference('branch', 'reference')
1053
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1054
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
1055
 
        new_branch.push(branch)
1056
 
        self.assertEqual('foo',
1057
 
                         branch.get_reference_info('file-id2')[1])
1058
 
 
1059
 
    def test_merge_updates_references(self):
1060
 
        branch = self.make_branch_with_reference('branch', 'reference')
1061
 
        tree = self.make_branch_and_tree('tree')
1062
 
        tree.commit('foo')
1063
 
        branch.pull(tree.branch)
1064
 
        checkout = branch.create_checkout('checkout', lightweight=True)
1065
 
        checkout.commit('bar')
1066
 
        tree.lock_write()
1067
 
        self.addCleanup(tree.unlock)
1068
 
        merger = merge.Merger.from_revision_ids(None, tree,
1069
 
                                                branch.last_revision(),
1070
 
                                                other_branch=branch)
1071
 
        merger.merge_type = merge.Merge3Merger
1072
 
        merger.do_merge()
1073
 
        self.assertEqual('../branch/reference',
1074
 
                         tree.branch.get_reference_info('file-id')[1])
1075
 
 
1076
 
 
1077
 
class TestBranchControlComponent(per_branch.TestCaseWithBranch):
1078
 
    """Branch implementations adequately implement ControlComponent."""
1079
 
 
1080
 
    def test_urls(self):
1081
 
        br = self.make_branch('branch')
1082
 
        self.assertIsInstance(br.user_url, str)
1083
 
        self.assertEqual(br.user_url, br.user_transport.base)
1084
 
        # for all current bzrdir implementations the user dir must be 
1085
 
        # above the control dir but we might need to relax that?
1086
 
        self.assertEqual(br.control_url.find(br.user_url), 0)
1087
 
        self.assertEqual(br.control_url, br.control_transport.base)
 
40
        from bzrlib.fetch import Fetcher
 
41
        os.mkdir('b1')
 
42
        os.mkdir('b2')
 
43
        b1 = Branch('b1', init=True)
 
44
        b2 = Branch('b2', init=True)
 
45
        file(os.sep.join(['b1', 'foo']), 'w').write('hello')
 
46
        b1.add(['foo'], ['foo-id'])
 
47
        b1.commit('lala!', rev_id='revision-1', allow_pointless=False)
 
48
 
 
49
        mutter('start fetch')
 
50
        f = Fetcher(from_branch=b1, to_branch=b2)
 
51
        eq = self.assertEquals
 
52
        eq(f.count_copied, 1)
 
53
        eq(f.last_revision, 'revision-1')
 
54
 
 
55
        rev = b2.get_revision('revision-1')
 
56
        tree = b2.revision_tree('revision-1')
 
57
        eq(tree.get_file_text('foo-id'), 'hello')
 
58
 
 
59
 
 
60
# TODO: rewrite this as a regular unittest, without relying on the displayed output        
 
61
#         >>> from bzrlib.commit import commit
 
62
#         >>> bzrlib.trace.silent = True
 
63
#         >>> br1 = ScratchBranch(files=['foo', 'bar'])
 
64
#         >>> br1.add('foo')
 
65
#         >>> br1.add('bar')
 
66
#         >>> commit(br1, "lala!", rev_id="REVISION-ID-1", verbose=False)
 
67
#         >>> br2 = ScratchBranch()
 
68
#         >>> br2.update_revisions(br1)
 
69
#         Added 2 texts.
 
70
#         Added 1 inventories.
 
71
#         Added 1 revisions.
 
72
#         >>> br2.revision_history()
 
73
#         [u'REVISION-ID-1']
 
74
#         >>> br2.update_revisions(br1)
 
75
#         Added 0 revisions.
 
76
#         >>> br1.text_store.total_size() == br2.text_store.total_size()
 
77
#         True