~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testbranch.py

  • Committer: Martin Pool
  • Date: 2005-09-01 06:32:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050901063252-00fc761bf1076759
- make target to build emacs TAGS file

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