~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/branch_implementations/test_branch.py

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2
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
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Tests for branch implementations - tests a branch format."""
18
18
 
19
 
import contextlib
 
19
import os
 
20
import sys
20
21
 
21
22
from bzrlib import (
22
 
    branch as _mod_branch,
23
 
    controldir,
24
 
    config,
25
 
    delta as _mod_delta,
 
23
    branch,
 
24
    bzrdir,
26
25
    errors,
27
 
    merge,
28
 
    osutils,
 
26
    gpg,
29
27
    urlutils,
30
 
    transform,
31
 
    transport,
 
28
    transactions,
32
29
    remote,
33
30
    repository,
34
 
    revision,
35
 
    shelf,
36
 
    symbol_versioning,
37
31
    tests,
38
32
    )
39
 
from bzrlib.tests import (
40
 
    per_branch,
41
 
    )
 
33
from bzrlib.branch import Branch, needs_read_lock, needs_write_lock
 
34
from bzrlib.delta import TreeDelta
 
35
from bzrlib.errors import (FileExists,
 
36
                           NoSuchRevision,
 
37
                           NoSuchFile,
 
38
                           UninitializableFormat,
 
39
                           NotBranchError,
 
40
                           )
 
41
from bzrlib.osutils import getcwd
 
42
import bzrlib.revision
 
43
from bzrlib.symbol_versioning import deprecated_in
 
44
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
45
from bzrlib.tests.branch_implementations import TestCaseWithBranch
42
46
from bzrlib.tests.http_server import HttpServer
43
 
from bzrlib.transport import memory
44
 
 
45
 
 
46
 
class TestTestCaseWithBranch(per_branch.TestCaseWithBranch):
47
 
 
48
 
    def test_branch_format_matches_bzrdir_branch_format(self):
49
 
        bzrdir_branch_format = self.bzrdir_format.get_branch_format()
50
 
        self.assertIs(self.branch_format.__class__,
51
 
                      bzrdir_branch_format.__class__)
52
 
 
53
 
    def test_make_branch_gets_expected_format(self):
54
 
        branch = self.make_branch('.')
55
 
        self.assertIs(self.branch_format.__class__,
56
 
            branch._format.__class__)
57
 
 
58
 
 
59
 
class TestBranch(per_branch.TestCaseWithBranch):
 
47
from bzrlib.trace import mutter
 
48
from bzrlib.transport import get_transport
 
49
from bzrlib.transport.memory import MemoryServer
 
50
from bzrlib.upgrade import upgrade
 
51
from bzrlib.workingtree import WorkingTree
 
52
 
 
53
 
 
54
class TestBranch(TestCaseWithBranch):
60
55
 
61
56
    def test_create_tree_with_merge(self):
62
57
        tree = self.create_tree_with_merge()
79
74
 
80
75
        br = self.get_branch()
81
76
        br.fetch(wt.branch)
82
 
        br.generate_revision_history('rev3')
83
 
        for revision_id in ['rev3', 'rev2', 'rev1']:
 
77
        br.set_revision_history(['rev1', 'rev2', 'rev3'])
 
78
        rh = br.revision_history()
 
79
        self.assertEqual(['rev1', 'rev2', 'rev3'], rh)
 
80
        for revision_id in rh:
84
81
            self.assertIsInstance(revision_id, str)
85
82
        last = br.last_revision()
86
83
        self.assertEqual('rev3', last)
99
96
        wt.commit('lala!', rev_id='revision-1', allow_pointless=False)
100
97
 
101
98
        b2 = self.make_branch('b2')
102
 
        b2.fetch(b1)
 
99
        self.assertEqual((1, []), b2.fetch(b1))
103
100
 
104
101
        rev = b2.repository.get_revision('revision-1')
105
102
        tree = b2.repository.revision_tree('revision-1')
116
113
        tree_a.add('vla', 'file2')
117
114
        tree_a.commit('rev2', rev_id='rev2')
118
115
 
119
 
        delta = self.applyDeprecated(symbol_versioning.deprecated_in(
120
 
            (2, 5, 0)), tree_a.branch.get_revision_delta, 1)
121
 
        self.assertIsInstance(delta, _mod_delta.TreeDelta)
 
116
        delta = tree_a.branch.get_revision_delta(1)
 
117
        self.assertIsInstance(delta, TreeDelta)
122
118
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
123
 
        delta = self.applyDeprecated(symbol_versioning.deprecated_in(
124
 
            (2, 5, 0)), tree_a.branch.get_revision_delta, 2)
125
 
        self.assertIsInstance(delta, _mod_delta.TreeDelta)
 
119
        delta = tree_a.branch.get_revision_delta(2)
 
120
        self.assertIsInstance(delta, TreeDelta)
126
121
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
127
122
 
128
123
    def get_unbalanced_tree_pair(self):
177
172
 
178
173
    def test_clone_branch_nickname(self):
179
174
        # test the nick name is preserved always
180
 
        raise tests.TestSkipped('XXX branch cloning is not yet tested.')
 
175
        raise TestSkipped('XXX branch cloning is not yet tested.')
181
176
 
182
177
    def test_clone_branch_parent(self):
183
178
        # test the parent is preserved always
189
184
        self.assertEqual(branch_b.get_parent(), branch_c.get_parent())
190
185
 
191
186
        # We can also set a specific parent, and it should be honored
192
 
        random_parent = 'http://example.com/path/to/branch'
 
187
        random_parent = 'http://bazaar-vcs.org/path/to/branch'
193
188
        branch_b.set_parent(random_parent)
194
189
        repo_d = self.make_repository('d')
195
190
        branch_b.repository.copy_content_into(repo_d)
204
199
        self.assertEqual(branch.get_submit_branch(), 'sftp://example.com')
205
200
        branch.set_submit_branch('sftp://example.net')
206
201
        self.assertEqual(branch.get_submit_branch(), 'sftp://example.net')
207
 
 
 
202
        
208
203
    def test_public_branch(self):
209
204
        """public location can be queried and set"""
210
205
        branch = self.make_branch('branch')
219
214
    def test_record_initial_ghost(self):
220
215
        """Branches should support having ghosts."""
221
216
        wt = self.make_branch_and_tree('.')
222
 
        if not wt.branch.repository._format.supports_ghosts:
223
 
            raise tests.TestNotApplicable("repository format does not "
224
 
                "support ghosts")
225
217
        wt.set_parent_ids(['non:existent@rev--ision--0--2'],
226
218
            allow_leftmost_as_ghost=True)
227
219
        self.assertEqual(['non:existent@rev--ision--0--2'],
235
227
    def test_record_two_ghosts(self):
236
228
        """Recording with all ghosts works."""
237
229
        wt = self.make_branch_and_tree('.')
238
 
        if not wt.branch.repository._format.supports_ghosts:
239
 
            raise tests.TestNotApplicable("repository format does not "
240
 
                "support ghosts")
241
230
        wt.set_parent_ids([
242
231
                'foo@azkhazan-123123-abcabc',
243
232
                'wibble@fofof--20050401--1928390812',
255
244
                          self.get_branch().repository.get_revision,
256
245
                          None)
257
246
 
258
 
    def test_nicks_bzr(self):
259
 
        """Test the behaviour of branch nicks specific to bzr branches.
260
 
 
 
247
# TODO 20051003 RBC:
 
248
# compare the gpg-to-sign info for a commit with a ghost and 
 
249
#     an identical tree without a ghost
 
250
# fetch missing should rewrite the TOC of weaves to list newly available parents.
 
251
        
 
252
    def test_sign_existing_revision(self):
 
253
        wt = self.make_branch_and_tree('.')
 
254
        branch = wt.branch
 
255
        wt.commit("base", allow_pointless=True, rev_id='A')
 
256
        from bzrlib.testament import Testament
 
257
        strategy = gpg.LoopbackGPGStrategy(None)
 
258
        branch.repository.lock_write()
 
259
        branch.repository.start_write_group()
 
260
        branch.repository.sign_revision('A', strategy)
 
261
        branch.repository.commit_write_group()
 
262
        branch.repository.unlock()
 
263
        self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
 
264
                         Testament.from_revision(branch.repository,
 
265
                         'A').as_short_text() +
 
266
                         '-----END PSEUDO-SIGNED CONTENT-----\n',
 
267
                         branch.repository.get_signature_text('A'))
 
268
 
 
269
    def test_store_signature(self):
 
270
        wt = self.make_branch_and_tree('.')
 
271
        branch = wt.branch
 
272
        branch.lock_write()
 
273
        try:
 
274
            branch.repository.start_write_group()
 
275
            try:
 
276
                branch.repository.store_revision_signature(
 
277
                    gpg.LoopbackGPGStrategy(None), 'FOO', 'A')
 
278
            except:
 
279
                branch.repository.abort_write_group()
 
280
                raise
 
281
            else:
 
282
                branch.repository.commit_write_group()
 
283
        finally:
 
284
            branch.unlock()
 
285
        # A signature without a revision should not be accessible.
 
286
        self.assertRaises(errors.NoSuchRevision,
 
287
                          branch.repository.has_signature_for_revision_id,
 
288
                          'A')
 
289
        wt.commit("base", allow_pointless=True, rev_id='A')
 
290
        self.assertEqual('-----BEGIN PSEUDO-SIGNED CONTENT-----\n'
 
291
                         'FOO-----END PSEUDO-SIGNED CONTENT-----\n',
 
292
                         branch.repository.get_signature_text('A'))
 
293
 
 
294
    def test_branch_keeps_signatures(self):
 
295
        wt = self.make_branch_and_tree('source')
 
296
        wt.commit('A', allow_pointless=True, rev_id='A')
 
297
        repo = wt.branch.repository
 
298
        repo.lock_write()
 
299
        repo.start_write_group()
 
300
        repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
 
301
        repo.commit_write_group()
 
302
        repo.unlock()
 
303
        #FIXME: clone should work to urls,
 
304
        # wt.clone should work to disks.
 
305
        self.build_tree(['target/'])
 
306
        d2 = repo.bzrdir.clone(urlutils.local_path_to_url('target'))
 
307
        self.assertEqual(repo.get_signature_text('A'),
 
308
                         d2.open_repository().get_signature_text('A'))
 
309
 
 
310
    def test_missing_revisions(self):
 
311
        t1 = self.make_branch_and_tree('b1')
 
312
        rev1 = t1.commit('one')
 
313
        t2 = t1.bzrdir.sprout('b2').open_workingtree()
 
314
        rev2 = t1.commit('two')
 
315
        rev3 = t1.commit('three')
 
316
 
 
317
        self.assertEqual([rev2, rev3],
 
318
            self.applyDeprecated(deprecated_in((1, 6, 0)),
 
319
            t2.branch.missing_revisions, t1.branch))
 
320
 
 
321
        self.assertEqual([],
 
322
            self.applyDeprecated(deprecated_in((1, 6, 0)),
 
323
            t2.branch.missing_revisions, t1.branch, stop_revision=1))
 
324
        self.assertEqual([rev2],
 
325
            self.applyDeprecated(deprecated_in((1, 6, 0)),
 
326
            t2.branch.missing_revisions, t1.branch, stop_revision=2))
 
327
        self.assertEqual([rev2, rev3],
 
328
            self.applyDeprecated(deprecated_in((1, 6, 0)),
 
329
            t2.branch.missing_revisions, t1.branch, stop_revision=3))
 
330
 
 
331
        self.assertRaises(errors.NoSuchRevision,
 
332
            self.applyDeprecated, deprecated_in((1, 6, 0)),
 
333
            t2.branch.missing_revisions, t1.branch, stop_revision=4)
 
334
 
 
335
        rev4 = t2.commit('four')
 
336
        self.assertRaises(errors.DivergedBranches,
 
337
            self.applyDeprecated, deprecated_in((1, 6, 0)),
 
338
            t2.branch.missing_revisions, t1.branch)
 
339
 
 
340
    def test_nicks(self):
 
341
        """Test explicit and implicit branch nicknames.
 
342
        
261
343
        Nicknames are implicitly the name of the branch's directory, unless an
262
344
        explicit nickname is set.  That is, an explicit nickname always
263
345
        overrides the implicit one.
264
 
 
265
346
        """
266
 
        t = self.get_transport()
 
347
        t = get_transport(self.get_url())
267
348
        branch = self.make_branch('bzr.dev')
268
 
        if not isinstance(branch, _mod_branch.BzrBranch):
269
 
            raise tests.TestNotApplicable("not a bzr branch format")
270
349
        # The nick will be 'bzr.dev', because there is no explicit nick set.
271
350
        self.assertEqual(branch.nick, 'bzr.dev')
272
351
        # Move the branch to a different directory, 'bzr.ab'.  Now that branch
273
352
        # will report its nick as 'bzr.ab'.
274
353
        t.move('bzr.dev', 'bzr.ab')
275
 
        branch = _mod_branch.Branch.open(self.get_url('bzr.ab'))
 
354
        branch = Branch.open(self.get_url('bzr.ab'))
276
355
        self.assertEqual(branch.nick, 'bzr.ab')
277
356
        # Set the branch nick explicitly.  This will ensure there's a branch
278
357
        # config file in the branch.
279
358
        branch.nick = "Aaron's branch"
280
359
        if not isinstance(branch, remote.RemoteBranch):
281
 
            self.assertTrue(branch._transport.has("branch.conf"))
 
360
            self.failUnless(branch._transport.has("branch.conf"))
282
361
        # Because the nick has been set explicitly, the nick is now always
283
362
        # "Aaron's branch", regardless of directory name.
284
363
        self.assertEqual(branch.nick, "Aaron's branch")
285
364
        t.move('bzr.ab', 'integration')
286
 
        branch = _mod_branch.Branch.open(self.get_url('integration'))
287
 
        self.assertEqual(branch.nick, "Aaron's branch")
288
 
        branch.nick = u"\u1234"
289
 
        self.assertEqual(branch.nick, u"\u1234")
290
 
 
291
 
    def test_nicks(self):
292
 
        """Test explicit and implicit branch nicknames.
293
 
 
294
 
        A nickname is always available, whether set explicitly or not.
295
 
        """
296
 
        t = self.get_transport()
297
 
        branch = self.make_branch('bzr.dev')
298
 
        # An implicit nick name is set; what it is exactly depends on the
299
 
        # format.
300
 
        self.assertIsInstance(branch.nick, basestring)
301
 
        # Set the branch nick explicitly.
302
 
        branch.nick = "Aaron's branch"
303
 
        # Because the nick has been set explicitly, the nick is now always
304
 
        # "Aaron's branch".
 
365
        branch = Branch.open(self.get_url('integration'))
305
366
        self.assertEqual(branch.nick, "Aaron's branch")
306
367
        branch.nick = u"\u1234"
307
368
        self.assertEqual(branch.nick, u"\u1234")
316
377
        self.assertEqual(committed.properties["branch-nick"],
317
378
                         "My happy branch")
318
379
 
319
 
    def test_create_colocated(self):
320
 
        try:
321
 
            repo = self.make_repository('.', shared=True)
322
 
        except errors.IncompatibleFormat:
323
 
            return
324
 
        if repo.bzrdir._format.colocated_branches:
325
 
            raise tests.TestNotApplicable(
326
 
                "control dir does not support colocated branches")
327
 
        self.assertEqual(0, len(repo.bzrdir.list_branches()))
328
 
        if not self.bzrdir_format.colocated_branches:
329
 
            raise tests.TestNotApplicable("control dir format does not support "
330
 
                "colocated branches")
331
 
        try:
332
 
            child_branch1 = self.branch_format.initialize(repo.bzrdir, 
333
 
                name='branch1')
334
 
        except errors.UninitializableFormat:
335
 
            # branch references are not default init'able and
336
 
            # not all bzrdirs support colocated branches.
337
 
            return
338
 
        self.assertEqual(1, len(repo.bzrdir.list_branches()))
339
 
        self.branch_format.initialize(repo.bzrdir, name='branch2')
340
 
        self.assertEqual(2, len(repo.bzrdir.list_branches()))
341
 
 
342
 
    def test_create_append_revisions_only(self):
343
 
        try:
344
 
            repo = self.make_repository('.', shared=True)
345
 
        except errors.IncompatibleFormat:
346
 
            return
347
 
        for val in (True, False):
348
 
            try:
349
 
                branch = self.branch_format.initialize(repo.bzrdir,
350
 
                    append_revisions_only=True)
351
 
            except (errors.UninitializableFormat, errors.UpgradeRequired):
352
 
                # branch references are not default init'able and
353
 
                # not all branches support append_revisions_only
354
 
                return
355
 
            self.assertEqual(True, branch.get_append_revisions_only())
356
 
            repo.bzrdir.destroy_branch()
357
 
 
358
 
    def test_get_set_append_revisions_only(self):
359
 
        branch = self.make_branch('.')
360
 
        if branch._format.supports_set_append_revisions_only():
361
 
            branch.set_append_revisions_only(True)
362
 
            self.assertTrue(branch.get_append_revisions_only())
363
 
            branch.set_append_revisions_only(False)
364
 
            self.assertFalse(branch.get_append_revisions_only())
365
 
        else:
366
 
            self.assertRaises(errors.UpgradeRequired,
367
 
                branch.set_append_revisions_only, True)
368
 
            self.assertFalse(branch.get_append_revisions_only())
369
 
 
370
380
    def test_create_open_branch_uses_repository(self):
371
381
        try:
372
382
            repo = self.make_repository('.', shared=True)
373
383
        except errors.IncompatibleFormat:
374
 
            raise tests.TestNotApplicable("requires shared repository support")
 
384
            return
375
385
        child_transport = repo.bzrdir.root_transport.clone('child')
376
386
        child_transport.mkdir('.')
377
 
        try:
378
 
            child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
379
 
        except errors.UninitializableFormat:
380
 
            raise tests.TestNotApplicable("control dir format not initializable")
 
387
        child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
381
388
        try:
382
389
            child_branch = self.branch_format.initialize(child_dir)
383
390
        except errors.UninitializableFormat:
385
392
            return
386
393
        self.assertEqual(repo.bzrdir.root_transport.base,
387
394
                         child_branch.repository.bzrdir.root_transport.base)
388
 
        child_branch = _mod_branch.Branch.open(self.get_url('child'))
 
395
        child_branch = branch.Branch.open(self.get_url('child'))
389
396
        self.assertEqual(repo.bzrdir.root_transport.base,
390
397
                         child_branch.repository.bzrdir.root_transport.base)
391
398
 
392
399
    def test_format_description(self):
393
400
        tree = self.make_branch_and_tree('tree')
394
401
        text = tree.branch._format.get_format_description()
395
 
        self.assertTrue(len(text))
 
402
        self.failUnless(len(text))
396
403
 
397
404
    def test_get_commit_builder(self):
398
405
        branch = self.make_branch(".")
406
413
        """Create a fake revision history easily."""
407
414
        tree = self.make_branch_and_tree('.')
408
415
        rev1 = tree.commit('foo')
409
 
        tree.lock_write()
410
 
        self.addCleanup(tree.unlock)
411
 
        graph = tree.branch.repository.get_graph()
412
 
        orig_history = list(
413
 
            graph.iter_lefthand_ancestry(
414
 
                tree.branch.last_revision(), [revision.NULL_REVISION]))
 
416
        orig_history = tree.branch.revision_history()
415
417
        rev2 = tree.commit('bar', allow_pointless=True)
416
418
        tree.branch.generate_revision_history(rev1)
417
 
        self.assertEqual(orig_history, list(
418
 
            graph.iter_lefthand_ancestry(
419
 
                tree.branch.last_revision(), [revision.NULL_REVISION])))
 
419
        self.assertEqual(orig_history, tree.branch.revision_history())
420
420
 
421
421
    def test_generate_revision_history_NULL_REVISION(self):
422
422
        tree = self.make_branch_and_tree('.')
423
423
        rev1 = tree.commit('foo')
424
 
        tree.lock_write()
425
 
        self.addCleanup(tree.unlock)
426
 
        tree.branch.generate_revision_history(revision.NULL_REVISION)
427
 
        self.assertEqual(revision.NULL_REVISION, tree.branch.last_revision())
 
424
        tree.branch.generate_revision_history(bzrlib.revision.NULL_REVISION)
 
425
        self.assertEqual([], tree.branch.revision_history())
428
426
 
429
427
    def test_create_checkout(self):
430
428
        tree_a = self.make_branch_and_tree('a')
441
439
        self.assertEqual('rev2', branch_a.last_revision())
442
440
        self.assertEqual(checkout_c.branch.base, branch_a.base)
443
441
 
 
442
        os.mkdir('d')
444
443
        checkout_d = branch_a.create_checkout('d', lightweight=True)
445
444
        self.assertEqual('rev2', checkout_d.last_revision())
 
445
        os.mkdir('e')
446
446
        checkout_e = branch_a.create_checkout('e')
447
447
        self.assertEqual('rev2', checkout_e.last_revision())
448
448
 
451
451
        tree_a = self.make_branch_and_tree('a')
452
452
        rev_id = tree_a.commit('put some content in the branch')
453
453
        # open the branch via a readonly transport
454
 
        url = self.get_readonly_url(urlutils.basename(tree_a.branch.base))
455
 
        t = transport.get_transport_from_url(url)
456
 
        if not tree_a.branch.bzrdir._format.supports_transport(t):
457
 
            raise tests.TestNotApplicable("format does not support transport")
458
 
        source_branch = _mod_branch.Branch.open(url)
 
454
        source_branch = bzrlib.branch.Branch.open(self.get_readonly_url('a'))
459
455
        # sanity check that the test will be valid
460
456
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
461
457
            source_branch.lock_write)
467
463
        tree_a = self.make_branch_and_tree('a')
468
464
        rev_id = tree_a.commit('put some content in the branch')
469
465
        # open the branch via a readonly transport
470
 
        url = self.get_readonly_url(
471
 
            osutils.basename(tree_a.branch.base.rstrip('/')))
472
 
        t = transport.get_transport_from_url(url)
473
 
        if not tree_a.branch.bzrdir._format.supports_transport(t):
474
 
            raise tests.TestNotApplicable("format does not support transport")
475
 
        source_branch = _mod_branch.Branch.open(url)
 
466
        source_branch = bzrlib.branch.Branch.open(self.get_readonly_url('a'))
476
467
        # sanity check that the test will be valid
477
468
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
478
469
            source_branch.lock_write)
479
470
        checkout = source_branch.create_checkout('c')
480
471
        self.assertEqual(rev_id, checkout.last_revision())
481
472
 
482
 
    def test_heads_to_fetch(self):
483
 
        # heads_to_fetch is a method that returns a collection of revids that
484
 
        # need to be fetched to copy this branch into another repo.  At a
485
 
        # minimum this will include the tip.
486
 
        # (In native formats, this is the tip + tags, but other formats may
487
 
        # have other revs needed)
488
 
        tree = self.make_branch_and_tree('a')
489
 
        tree.commit('first commit', rev_id='rev1')
490
 
        tree.commit('second commit', rev_id='rev2')
491
 
        must_fetch, should_fetch = tree.branch.heads_to_fetch()
492
 
        self.assertTrue('rev2' in must_fetch)
493
 
 
494
 
    def test_heads_to_fetch_not_null_revision(self):
495
 
        # NULL_REVISION does not appear in the result of heads_to_fetch, even
496
 
        # for an empty branch.
497
 
        tree = self.make_branch_and_tree('a')
498
 
        must_fetch, should_fetch = tree.branch.heads_to_fetch()
499
 
        self.assertFalse(revision.NULL_REVISION in must_fetch)
500
 
        self.assertFalse(revision.NULL_REVISION in should_fetch)
501
 
 
502
 
 
503
 
class TestBranchFormat(per_branch.TestCaseWithBranch):
504
 
 
505
 
    def test_branch_format_network_name(self):
506
 
        br = self.make_branch('.')
507
 
        format = br._format
508
 
        network_name = format.network_name()
509
 
        self.assertIsInstance(network_name, str)
510
 
        # We want to test that the network_name matches the actual format on
511
 
        # disk. For local branches that means that using network_name as a key
512
 
        # in the registry gives back the same format. For remote branches we
513
 
        # check that the network_name of the RemoteBranchFormat we have locally
514
 
        # matches the actual format present on disk.
515
 
        if isinstance(format, remote.RemoteBranchFormat):
516
 
            br._ensure_real()
517
 
            real_branch = br._real_branch
518
 
            self.assertEqual(real_branch._format.network_name(), network_name)
519
 
        else:
520
 
            registry = _mod_branch.network_format_registry
521
 
            looked_up_format = registry.get(network_name)
522
 
            self.assertEqual(format.__class__, looked_up_format.__class__)
523
 
 
524
 
    def test_get_config_calls(self):
525
 
        # Smoke test that all branch succeed getting a config
526
 
        br = self.make_branch('.')
527
 
        br.get_config()
528
 
        br.get_config_stack()
529
 
 
530
 
 
531
 
class ChrootedTests(per_branch.TestCaseWithBranch):
 
473
    def test_set_revision_history(self):
 
474
        tree = self.make_branch_and_tree('a')
 
475
        tree.commit('a commit', rev_id='rev1')
 
476
        br = tree.branch
 
477
        br.set_revision_history(["rev1"])
 
478
        self.assertEquals(br.revision_history(), ["rev1"])
 
479
        br.set_revision_history([])
 
480
        self.assertEquals(br.revision_history(), [])
 
481
 
 
482
 
 
483
class ChrootedTests(TestCaseWithBranch):
532
484
    """A support class that provides readonly urls outside the local namespace.
533
485
 
534
486
    This is done by checking if self.transport_server is a MemoryServer. if it
538
490
 
539
491
    def setUp(self):
540
492
        super(ChrootedTests, self).setUp()
541
 
        if not self.vfs_transport_factory == memory.MemoryServer:
 
493
        if not self.vfs_transport_factory == MemoryServer:
542
494
            self.transport_readonly_server = HttpServer
543
495
 
544
496
    def test_open_containing(self):
545
 
        self.assertRaises(errors.NotBranchError,
546
 
                          _mod_branch.Branch.open_containing,
 
497
        self.assertRaises(NotBranchError, Branch.open_containing,
547
498
                          self.get_readonly_url(''))
548
 
        self.assertRaises(errors.NotBranchError,
549
 
                          _mod_branch.Branch.open_containing,
 
499
        self.assertRaises(NotBranchError, Branch.open_containing,
550
500
                          self.get_readonly_url('g/p/q'))
551
501
        branch = self.make_branch('.')
552
 
        if not branch.bzrdir._format.supports_transport(
553
 
            transport.get_transport_from_url(self.get_readonly_url('.'))):
554
 
            raise tests.TestNotApplicable("format does not support transport")
555
 
        branch, relpath = _mod_branch.Branch.open_containing(
556
 
            self.get_readonly_url(''))
 
502
        branch, relpath = Branch.open_containing(self.get_readonly_url(''))
557
503
        self.assertEqual('', relpath)
558
 
        branch, relpath = _mod_branch.Branch.open_containing(
559
 
            self.get_readonly_url('g/p/q'))
 
504
        branch, relpath = Branch.open_containing(self.get_readonly_url('g/p/q'))
560
505
        self.assertEqual('g/p/q', relpath)
561
 
 
 
506
        
562
507
 
563
508
class InstrumentedTransaction(object):
564
509
 
583
528
    def unlock(self):
584
529
        self._calls.append('ul')
585
530
 
586
 
    @_mod_branch.needs_read_lock
 
531
    @needs_read_lock
587
532
    def do_with_read(self):
588
533
        return 1
589
534
 
590
 
    @_mod_branch.needs_read_lock
 
535
    @needs_read_lock
591
536
    def except_with_read(self):
592
537
        raise RuntimeError
593
538
 
594
 
    @_mod_branch.needs_write_lock
 
539
    @needs_write_lock
595
540
    def do_with_write(self):
596
541
        return 2
597
542
 
598
 
    @_mod_branch.needs_write_lock
 
543
    @needs_write_lock
599
544
    def except_with_write(self):
600
545
        raise RuntimeError
601
546
 
602
547
 
603
 
class TestDecorators(tests.TestCase):
 
548
class TestDecorators(TestCase):
604
549
 
605
550
    def test_needs_read_lock(self):
606
551
        branch = TestDecorator()
623
568
        self.assertEqual(['lw', 'ul'], branch._calls)
624
569
 
625
570
 
626
 
class TestBranchPushLocations(per_branch.TestCaseWithBranch):
 
571
class TestBranchPushLocations(TestCaseWithBranch):
627
572
 
628
573
    def test_get_push_location_unset(self):
629
574
        self.assertEqual(None, self.get_branch().get_push_location())
630
575
 
631
576
    def test_get_push_location_exact(self):
632
 
        b = self.get_branch()
633
 
        config.LocationConfig.from_string(
634
 
            '[%s]\npush_location=foo\n' % (b.base,), b.base, save=True)
 
577
        from bzrlib.config import (locations_config_filename,
 
578
                                   ensure_config_dir_exists)
 
579
        ensure_config_dir_exists()
 
580
        fn = locations_config_filename()
 
581
        open(fn, 'wt').write(("[%s]\n"
 
582
                                  "push_location=foo\n" %
 
583
                                  self.get_branch().base[:-1]))
635
584
        self.assertEqual("foo", self.get_branch().get_push_location())
636
585
 
637
586
    def test_set_push_location(self):
640
589
        self.assertEqual('foo', branch.get_push_location())
641
590
 
642
591
 
643
 
class TestChildSubmitFormats(per_branch.TestCaseWithBranch):
644
 
 
645
 
    def test_get_child_submit_format_default(self):
646
 
        submit_format = self.get_branch().get_child_submit_format()
647
 
        self.assertTrue(submit_format is None or
648
 
                        isinstance(submit_format, str))
649
 
 
650
 
    def test_get_child_submit_format(self):
651
 
        branch = self.get_branch()
652
 
        branch.get_config_stack().set('child_submit_format', '10')
653
 
        branch = self.get_branch()
654
 
        self.assertEqual('10', branch.get_child_submit_format())
655
 
 
656
 
 
657
 
class TestFormat(per_branch.TestCaseWithBranch):
 
592
class TestFormat(TestCaseWithBranch):
658
593
    """Tests for the format itself."""
659
594
 
660
595
    def test_get_reference(self):
678
613
        this_branch = self.make_branch('this')
679
614
        other_branch = self.make_branch('other')
680
615
        try:
681
 
            this_branch._format.set_reference(this_branch.bzrdir, None,
682
 
                other_branch)
 
616
            this_branch._format.set_reference(this_branch.bzrdir, other_branch)
683
617
        except NotImplementedError:
684
618
            # that's ok
685
619
            pass
695
629
            # they may not be initializable.
696
630
            return
697
631
        # supported formats must be able to init and open
698
 
        t = self.get_transport()
699
 
        readonly_t = transport.get_transport_from_url(self.get_readonly_url())
 
632
        t = get_transport(self.get_url())
 
633
        readonly_t = get_transport(self.get_readonly_url())
700
634
        made_branch = self.make_branch('.')
701
 
        self.assertIsInstance(made_branch, _mod_branch.Branch)
 
635
        self.failUnless(isinstance(made_branch, branch.Branch))
702
636
 
703
637
        # find it via bzrdir opening:
704
 
        opened_control = controldir.ControlDir.open(readonly_t.base)
 
638
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
705
639
        direct_opened_branch = opened_control.open_branch()
706
640
        self.assertEqual(direct_opened_branch.__class__, made_branch.__class__)
707
641
        self.assertEqual(opened_control, direct_opened_branch.bzrdir)
708
 
        self.assertIsInstance(direct_opened_branch._format,
709
 
            self.branch_format.__class__)
 
642
        self.failUnless(isinstance(direct_opened_branch._format,
 
643
                        self.branch_format.__class__))
710
644
 
711
645
        # find it via Branch.open
712
 
        opened_branch = _mod_branch.Branch.open(readonly_t.base)
713
 
        self.assertIsInstance(opened_branch, made_branch.__class__)
 
646
        opened_branch = branch.Branch.open(readonly_t.base)
 
647
        self.failUnless(isinstance(opened_branch, made_branch.__class__))
714
648
        self.assertEqual(made_branch._format.__class__,
715
649
                         opened_branch._format.__class__)
716
650
        # if it has a unique id string, can we probe for it ?
722
656
                         opened_control.find_branch_format())
723
657
 
724
658
 
725
 
class TestBound(per_branch.TestCaseWithBranch):
 
659
class TestBound(TestCaseWithBranch):
726
660
 
727
661
    def test_bind_unbind(self):
728
662
        branch = self.make_branch('1')
759
693
        except errors.UpgradeRequired:
760
694
            raise tests.TestNotApplicable('Format does not support binding')
761
695
 
762
 
    def test_unbind_clears_cached_master_branch(self):
763
 
        """b.unbind clears any cached value of b.get_master_branch."""
764
 
        master = self.make_branch('master')
765
 
        branch = self.make_branch('branch')
766
 
        try:
767
 
            branch.bind(master)
768
 
        except errors.UpgradeRequired:
769
 
            raise tests.TestNotApplicable('Format does not support binding')
770
 
        self.addCleanup(branch.lock_write().unlock)
771
 
        self.assertNotEqual(None, branch.get_master_branch())
772
 
        branch.unbind()
773
 
        self.assertEqual(None, branch.get_master_branch())
774
 
 
775
 
    def test_bind_clears_cached_master_branch(self):
776
 
        """b.bind clears any cached value of b.get_master_branch."""
777
 
        master1 = self.make_branch('master1')
778
 
        master2 = self.make_branch('master2')
779
 
        branch = self.make_branch('branch')
780
 
        try:
781
 
            branch.bind(master1)
782
 
        except errors.UpgradeRequired:
783
 
            raise tests.TestNotApplicable('Format does not support binding')
784
 
        self.addCleanup(branch.lock_write().unlock)
785
 
        self.assertNotEqual(None, branch.get_master_branch())
786
 
        branch.bind(master2)
787
 
        self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
788
 
                branch.get_master_branch().base))
789
 
 
790
 
    def test_set_bound_location_clears_cached_master_branch(self):
791
 
        """b.set_bound_location clears any cached value of b.get_master_branch.
792
 
        """
793
 
        master1 = self.make_branch('master1')
794
 
        master2 = self.make_branch('master2')
795
 
        branch = self.make_branch('branch')
796
 
        try:
797
 
            branch.bind(master1)
798
 
        except errors.UpgradeRequired:
799
 
            raise tests.TestNotApplicable('Format does not support binding')
800
 
        self.addCleanup(branch.lock_write().unlock)
801
 
        self.assertNotEqual(None, branch.get_master_branch())
802
 
        branch.set_bound_location(self.get_url('master2'))
803
 
        self.assertEqual('.', urlutils.relative_url(self.get_url('master2'),
804
 
                branch.get_master_branch().base))
805
 
 
806
 
 
807
 
class TestStrict(per_branch.TestCaseWithBranch):
 
696
 
 
697
class TestStrict(TestCaseWithBranch):
808
698
 
809
699
    def test_strict_history(self):
810
700
        tree1 = self.make_branch_and_tree('tree1')
811
701
        try:
812
702
            tree1.branch.set_append_revisions_only(True)
813
703
        except errors.UpgradeRequired:
814
 
            raise tests.TestSkipped('Format does not support strict history')
 
704
            raise TestSkipped('Format does not support strict history')
815
705
        tree1.commit('empty commit')
816
706
        tree2 = tree1.bzrdir.sprout('tree2').open_workingtree()
817
707
        tree2.commit('empty commit 2')
827
717
        tree3.merge_from_branch(tree2.branch)
828
718
        tree3.commit('empty commit 6')
829
719
        tree2.pull(tree3.branch)
830
 
 
831
 
 
832
 
class TestIgnoreFallbacksParameter(per_branch.TestCaseWithBranch):
833
 
 
834
 
    def make_branch_with_fallback(self):
835
 
        fallback = self.make_branch('fallback')
836
 
        if not fallback._format.supports_stacking():
837
 
            raise tests.TestNotApplicable("format does not support stacking")
838
 
        stacked = self.make_branch('stacked')
839
 
        stacked.set_stacked_on_url(fallback.base)
840
 
        return stacked
841
 
 
842
 
    def test_fallbacks_not_opened(self):
843
 
        stacked = self.make_branch_with_fallback()
844
 
        self.get_transport('').rename('fallback', 'moved')
845
 
        reopened_dir = controldir.ControlDir.open(stacked.base)
846
 
        reopened = reopened_dir.open_branch(ignore_fallbacks=True)
847
 
        self.assertEqual([], reopened.repository._fallback_repositories)
848
 
 
849
 
    def test_fallbacks_are_opened(self):
850
 
        stacked = self.make_branch_with_fallback()
851
 
        reopened_dir = controldir.ControlDir.open(stacked.base)
852
 
        reopened = reopened_dir.open_branch(ignore_fallbacks=False)
853
 
        self.assertLength(1, reopened.repository._fallback_repositories)
854
 
 
855
 
 
856
 
class TestReferenceLocation(per_branch.TestCaseWithBranch):
857
 
 
858
 
    def test_reference_parent(self):
859
 
        tree = self.make_branch_and_tree('tree')
860
 
        subtree = self.make_branch_and_tree('tree/subtree')
861
 
        subtree.set_root_id('subtree-id')
862
 
        try:
863
 
            tree.add_reference(subtree)
864
 
        except errors.UnsupportedOperation:
865
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
866
 
        reference_parent = tree.branch.reference_parent(
867
 
            'subtree-id',
868
 
            urlutils.relative_url(tree.branch.user_url, subtree.branch.user_url))
869
 
        self.assertEqual(subtree.branch.base, reference_parent.base)
870
 
 
871
 
    def test_reference_parent_accepts_possible_transports(self):
872
 
        tree = self.make_branch_and_tree('tree')
873
 
        subtree = self.make_branch_and_tree('tree/subtree')
874
 
        subtree.set_root_id('subtree-id')
875
 
        try:
876
 
            tree.add_reference(subtree)
877
 
        except errors.UnsupportedOperation:
878
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
879
 
        reference_parent = tree.branch.reference_parent('subtree-id',
880
 
            urlutils.relative_url(
881
 
                tree.branch.user_url, subtree.branch.user_url),
882
 
            possible_transports=[subtree.bzrdir.root_transport])
883
 
 
884
 
    def test_get_reference_info(self):
885
 
        branch = self.make_branch('branch')
886
 
        try:
887
 
            path, loc = branch.get_reference_info('file-id')
888
 
        except errors.UnsupportedOperation:
889
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
890
 
        self.assertIs(None, path)
891
 
        self.assertIs(None, loc)
892
 
 
893
 
    def test_set_reference_info(self):
894
 
        branch = self.make_branch('branch')
895
 
        try:
896
 
            branch.set_reference_info('file-id', 'path/to/location',
897
 
                                      'path/to/file')
898
 
        except errors.UnsupportedOperation:
899
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
900
 
 
901
 
    def test_set_get_reference_info(self):
902
 
        branch = self.make_branch('branch')
903
 
        try:
904
 
            branch.set_reference_info('file-id', 'path/to/file',
905
 
                                      'path/to/location')
906
 
        except errors.UnsupportedOperation:
907
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
908
 
        # Create a new instance to ensure storage is permanent
909
 
        branch = _mod_branch.Branch.open('branch')
910
 
        tree_path, branch_location = branch.get_reference_info('file-id')
911
 
        self.assertEqual('path/to/location', branch_location)
912
 
 
913
 
    def test_set_null_reference_info(self):
914
 
        branch = self.make_branch('branch')
915
 
        try:
916
 
            branch.set_reference_info('file-id', 'path/to/file',
917
 
                                      'path/to/location')
918
 
        except errors.UnsupportedOperation:
919
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
920
 
        branch.set_reference_info('file-id', None, None)
921
 
        tree_path, branch_location = branch.get_reference_info('file-id')
922
 
        self.assertIs(None, tree_path)
923
 
        self.assertIs(None, branch_location)
924
 
 
925
 
    def test_set_null_reference_info_when_null(self):
926
 
        branch = self.make_branch('branch')
927
 
        try:
928
 
            tree_path, branch_location = branch.get_reference_info('file-id')
929
 
        except errors.UnsupportedOperation:
930
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
931
 
        self.assertIs(None, tree_path)
932
 
        self.assertIs(None, branch_location)
933
 
        branch.set_reference_info('file-id', None, None)
934
 
 
935
 
    def test_set_null_requires_two_nones(self):
936
 
        branch = self.make_branch('branch')
937
 
        try:
938
 
            e = self.assertRaises(ValueError, branch.set_reference_info,
939
 
                                  'file-id', 'path', None)
940
 
        except errors.UnsupportedOperation:
941
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
942
 
        self.assertEqual('tree_path must be None when branch_location is'
943
 
                         ' None.', str(e))
944
 
        e = self.assertRaises(ValueError, branch.set_reference_info,
945
 
                              'file-id', None, 'location')
946
 
        self.assertEqual('branch_location must be None when tree_path is'
947
 
                         ' None.', str(e))
948
 
 
949
 
    def make_branch_with_reference(self, location, reference_location,
950
 
                                   file_id='file-id'):
951
 
        branch = self.make_branch(location)
952
 
        try:
953
 
            branch.set_reference_info(file_id, 'path/to/file',
954
 
                                      reference_location)
955
 
        except errors.UnsupportedOperation:
956
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
957
 
        return branch
958
 
 
959
 
    def test_reference_parent_from_reference_info_(self):
960
 
        referenced_branch = self.make_branch('reference_branch')
961
 
        branch = self.make_branch_with_reference('branch',
962
 
                                                 referenced_branch.base)
963
 
        parent = branch.reference_parent('file-id', 'path/to/file')
964
 
        self.assertEqual(parent.base, referenced_branch.base)
965
 
 
966
 
    def test_branch_relative_reference_location(self):
967
 
        branch = self.make_branch('branch')
968
 
        try:
969
 
            branch.set_reference_info('file-id', 'path/to/file',
970
 
            '../reference_branch')
971
 
        except errors.UnsupportedOperation:
972
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
973
 
        referenced_branch = self.make_branch('reference_branch')
974
 
        parent = branch.reference_parent('file-id', 'path/to/file')
975
 
        self.assertEqual(parent.base, referenced_branch.base)
976
 
 
977
 
    def test_sprout_copies_reference_location(self):
978
 
        branch = self.make_branch_with_reference('branch', '../reference')
979
 
        new_branch = branch.bzrdir.sprout('new-branch').open_branch()
980
 
        self.assertEqual('../reference',
981
 
                         new_branch.get_reference_info('file-id')[1])
982
 
 
983
 
    def test_clone_copies_reference_location(self):
984
 
        branch = self.make_branch_with_reference('branch', '../reference')
985
 
        new_branch = branch.bzrdir.clone('new-branch').open_branch()
986
 
        self.assertEqual('../reference',
987
 
                         new_branch.get_reference_info('file-id')[1])
988
 
 
989
 
    def test_copied_locations_are_rebased(self):
990
 
        branch = self.make_branch_with_reference('branch', 'reference')
991
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
992
 
        self.assertEqual('../reference',
993
 
                         new_branch.get_reference_info('file-id')[1])
994
 
 
995
 
    def test_update_references_retains_old_references(self):
996
 
        branch = self.make_branch_with_reference('branch', 'reference')
997
 
        new_branch = self.make_branch_with_reference(
998
 
            'new_branch', 'reference', 'file-id2')
999
 
        new_branch.update_references(branch)
1000
 
        self.assertEqual('reference',
1001
 
                         branch.get_reference_info('file-id')[1])
1002
 
 
1003
 
    def test_update_references_retains_known_references(self):
1004
 
        branch = self.make_branch_with_reference('branch', 'reference')
1005
 
        new_branch = self.make_branch_with_reference(
1006
 
            'new_branch', 'reference2')
1007
 
        new_branch.update_references(branch)
1008
 
        self.assertEqual('reference',
1009
 
                         branch.get_reference_info('file-id')[1])
1010
 
 
1011
 
    def test_update_references_skips_known_references(self):
1012
 
        branch = self.make_branch_with_reference('branch', 'reference')
1013
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1014
 
        new_branch.set_reference_info('file-id', '../foo', '../foo')
1015
 
        new_branch.update_references(branch)
1016
 
        self.assertEqual('reference',
1017
 
                         branch.get_reference_info('file-id')[1])
1018
 
 
1019
 
    def test_pull_updates_references(self):
1020
 
        branch = self.make_branch_with_reference('branch', 'reference')
1021
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1022
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
1023
 
        branch.pull(new_branch)
1024
 
        self.assertEqual('foo',
1025
 
                         branch.get_reference_info('file-id2')[1])
1026
 
 
1027
 
    def test_push_updates_references(self):
1028
 
        branch = self.make_branch_with_reference('branch', 'reference')
1029
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
1030
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
1031
 
        new_branch.push(branch)
1032
 
        self.assertEqual('foo',
1033
 
                         branch.get_reference_info('file-id2')[1])
1034
 
 
1035
 
    def test_merge_updates_references(self):
1036
 
        branch = self.make_branch_with_reference('branch', 'reference')
1037
 
        tree = self.make_branch_and_tree('tree')
1038
 
        tree.commit('foo')
1039
 
        branch.pull(tree.branch)
1040
 
        checkout = branch.create_checkout('checkout', lightweight=True)
1041
 
        checkout.commit('bar')
1042
 
        tree.lock_write()
1043
 
        self.addCleanup(tree.unlock)
1044
 
        merger = merge.Merger.from_revision_ids(None, tree,
1045
 
                                                branch.last_revision(),
1046
 
                                                other_branch=branch)
1047
 
        merger.merge_type = merge.Merge3Merger
1048
 
        merger.do_merge()
1049
 
        self.assertEqual('../branch/reference',
1050
 
                         tree.branch.get_reference_info('file-id')[1])
1051
 
 
1052
 
 
1053
 
class TestBranchControlComponent(per_branch.TestCaseWithBranch):
1054
 
    """Branch implementations adequately implement ControlComponent."""
1055
 
 
1056
 
    def test_urls(self):
1057
 
        br = self.make_branch('branch')
1058
 
        self.assertIsInstance(br.user_url, str)
1059
 
        self.assertEqual(br.user_url, br.user_transport.base)
1060
 
        # for all current bzrdir implementations the user dir must be 
1061
 
        # above the control dir but we might need to relax that?
1062
 
        self.assertEqual(br.control_url.find(br.user_url), 0)
1063
 
        self.assertEqual(br.control_url, br.control_transport.base)
1064
 
 
1065
 
 
1066
 
class FakeShelfCreator(object):
1067
 
 
1068
 
    def __init__(self, branch):
1069
 
        self.branch = branch
1070
 
 
1071
 
    def write_shelf(self, shelf_file, message=None):
1072
 
        tree = self.branch.repository.revision_tree(revision.NULL_REVISION)
1073
 
        with transform.TransformPreview(tree) as tt:
1074
 
            shelf.ShelfCreator._write_shelf(
1075
 
                shelf_file, tt, revision.NULL_REVISION)
1076
 
 
1077
 
 
1078
 
@contextlib.contextmanager
1079
 
def skip_if_storing_uncommitted_unsupported():
1080
 
    try:
1081
 
        yield
1082
 
    except errors.StoringUncommittedNotSupported:
1083
 
        raise tests.TestNotApplicable('Cannot store uncommitted changes.')
1084
 
 
1085
 
 
1086
 
class TestUncommittedChanges(per_branch.TestCaseWithBranch):
1087
 
 
1088
 
    def bind(self, branch, master):
1089
 
        try:
1090
 
            branch.bind(master)
1091
 
        except errors.UpgradeRequired:
1092
 
            raise tests.TestNotApplicable('Branch cannot be bound.')
1093
 
 
1094
 
    def test_store_uncommitted(self):
1095
 
        tree = self.make_branch_and_tree('b')
1096
 
        branch = tree.branch
1097
 
        creator = FakeShelfCreator(branch)
1098
 
        with skip_if_storing_uncommitted_unsupported():
1099
 
            self.assertIs(None, branch.get_unshelver(tree))
1100
 
        branch.store_uncommitted(creator)
1101
 
        self.assertIsNot(None, branch.get_unshelver(tree))
1102
 
 
1103
 
    def test_store_uncommitted_bound(self):
1104
 
        tree = self.make_branch_and_tree('b')
1105
 
        branch = tree.branch
1106
 
        master = self.make_branch('master')
1107
 
        self.bind(branch, master)
1108
 
        creator = FakeShelfCreator(tree.branch)
1109
 
        self.assertIs(None, tree.branch.get_unshelver(tree))
1110
 
        self.assertIs(None, master.get_unshelver(tree))
1111
 
        tree.branch.store_uncommitted(creator)
1112
 
        self.assertIsNot(None, master.get_unshelver(tree))
1113
 
 
1114
 
    def test_store_uncommitted_already_stored(self):
1115
 
        branch = self.make_branch('b')
1116
 
        with skip_if_storing_uncommitted_unsupported():
1117
 
            branch.store_uncommitted(FakeShelfCreator(branch))
1118
 
        self.assertRaises(errors.ChangesAlreadyStored,
1119
 
                          branch.store_uncommitted, FakeShelfCreator(branch))
1120
 
 
1121
 
    def test_store_uncommitted_none(self):
1122
 
        branch = self.make_branch('b')
1123
 
        with skip_if_storing_uncommitted_unsupported():
1124
 
            branch.store_uncommitted(FakeShelfCreator(branch))
1125
 
        branch.store_uncommitted(None)
1126
 
        self.assertIs(None, branch.get_unshelver(None))
1127
 
 
1128
 
    def test_get_unshelver(self):
1129
 
        tree = self.make_branch_and_tree('tree')
1130
 
        tree.commit('')
1131
 
        self.build_tree_contents([('tree/file', 'contents1')])
1132
 
        tree.add('file')
1133
 
        with skip_if_storing_uncommitted_unsupported():
1134
 
            tree.store_uncommitted()
1135
 
        unshelver = tree.branch.get_unshelver(tree)
1136
 
        self.assertIsNot(None, unshelver)
1137
 
 
1138
 
    def test_get_unshelver_bound(self):
1139
 
        tree = self.make_branch_and_tree('tree')
1140
 
        tree.commit('')
1141
 
        self.build_tree_contents([('tree/file', 'contents1')])
1142
 
        tree.add('file')
1143
 
        with skip_if_storing_uncommitted_unsupported():
1144
 
            tree.store_uncommitted()
1145
 
        branch = self.make_branch('branch')
1146
 
        self.bind(branch, tree.branch)
1147
 
        unshelver = branch.get_unshelver(tree)
1148
 
        self.assertIsNot(None, unshelver)