~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testbranch.py

  • Committer: Aaron Bentley
  • Date: 2005-07-26 14:06:11 UTC
  • mto: (1092.1.41) (1185.3.4) (974.1.47)
  • mto: This revision was merged to the branch mainline in revision 982.
  • Revision ID: abentley@panoramicfeedback.com-20050726140611-403e366f3c79c1f1
Fixed python invocation

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