~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testbranch.py

  • Committer: Martin Pool
  • Date: 2005-07-28 11:56:24 UTC
  • Revision ID: mbp@sourcefrog.net-20050728115624-93c11c2b1e399023
- note changes to command line parsing

Show diffs side-by-side

added added

removed removed

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