~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch_implementations.py

UnfuckĀ upgrade.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2
 
#
 
1
# (C) 2005, 2006 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
 
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
 
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.memory import MemoryServer
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
 
 
 
19
import os
 
20
import sys
 
21
 
 
22
import bzrlib.branch as branch
 
23
from bzrlib.branch import Branch, needs_read_lock, needs_write_lock
 
24
from bzrlib.clone import copy_branch
 
25
from bzrlib.commit import commit
 
26
import bzrlib.errors as errors
 
27
from bzrlib.errors import (NoSuchRevision,
 
28
                           NoSuchFile,
 
29
                           UninitializableFormat,
 
30
                           NotBranchError,
 
31
                           )
 
32
import bzrlib.gpg
 
33
from bzrlib.osutils import getcwd
 
34
from bzrlib.tests import TestCase, TestCaseInTempDir, TestSkipped
 
35
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
 
36
from bzrlib.trace import mutter
 
37
import bzrlib.transactions as transactions
 
38
from bzrlib.transport import get_transport
 
39
from bzrlib.revision import NULL_REVISION
 
40
 
 
41
# TODO: Make a branch using basis branch, and check that it 
 
42
# doesn't request any files that could have been avoided, by 
 
43
# hooking into the Transport.
 
44
 
 
45
 
 
46
class TestCaseWithBranch(TestCaseInTempDir):
 
47
 
 
48
    def setUp(self):
 
49
        super(TestCaseWithBranch, self).setUp()
 
50
        self.branch = None
 
51
 
 
52
    def get_branch(self):
 
53
        if self.branch is None:
 
54
            self.branch = self.make_branch('.')
 
55
        return self.branch
 
56
 
 
57
    def make_branch(self, relpath):
 
58
        try:
 
59
            return self.branch_format.initialize(relpath)
 
60
        except UninitializableFormat:
 
61
            raise TestSkipped("Format %s is not initializable.")
 
62
 
 
63
 
 
64
class TestBranch(TestCaseWithBranch):
 
65
 
 
66
    def test_append_revisions(self):
 
67
        """Test appending more than one revision"""
77
68
        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)
 
69
        br.append_revision("rev1")
 
70
        self.assertEquals(br.revision_history(), ["rev1",])
 
71
        br.append_revision("rev2", "rev3")
 
72
        self.assertEquals(br.revision_history(), ["rev1", "rev2", "rev3"])
91
73
 
92
74
    def test_fetch_revisions(self):
93
75
        """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
 
 
 
76
        from bzrlib.fetch import Fetcher
 
77
        os.mkdir('b1')
 
78
        os.mkdir('b2')
 
79
        b1 = self.make_branch('b1')
100
80
        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):
 
81
        file('b1/foo', 'w').write('hello')
 
82
        b1.working_tree().add(['foo'], ['foo-id'])
 
83
        b1.working_tree().commit('lala!', rev_id='revision-1', allow_pointless=False)
 
84
 
 
85
        mutter('start fetch')
 
86
        f = Fetcher(from_branch=b1, to_branch=b2)
 
87
        eq = self.assertEquals
 
88
        eq(f.count_copied, 1)
 
89
        eq(f.last_revision, 'revision-1')
 
90
 
 
91
        rev = b2.get_revision('revision-1')
 
92
        tree = b2.revision_tree('revision-1')
 
93
        eq(tree.get_file_text('foo-id'), 'hello')
 
94
 
 
95
    def test_revision_tree(self):
 
96
        b1 = self.get_branch()
 
97
        b1.working_tree().commit('lala!', rev_id='revision-1', allow_pointless=True)
 
98
        tree = b1.revision_tree('revision-1')
 
99
        tree = b1.revision_tree(None)
 
100
        self.assertEqual(len(tree.list_files()), 0)
 
101
        tree = b1.revision_tree(NULL_REVISION)
 
102
        self.assertEqual(len(tree.list_files()), 0)
 
103
 
 
104
    def get_unbalanced_branch_pair(self):
126
105
        """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
 
106
        os.mkdir('a')
 
107
        br_a = self.make_branch('a')
 
108
        file('a/b', 'wb').write('b')
 
109
        br_a.working_tree().add('b')
 
110
        commit(br_a, "silly commit", rev_id='A')
 
111
        os.mkdir('b')
 
112
        br_b = self.make_branch('b')
 
113
        return br_a, br_b
134
114
 
135
115
    def get_balanced_branch_pair(self):
136
116
        """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):
 
117
        br_a, br_b = self.get_unbalanced_branch_pair()
 
118
        br_a.push_stores(br_b)
 
119
        return br_a, br_b
 
120
 
 
121
    def test_push_stores(self):
 
122
        """Copy the stores from one branch to another"""
 
123
        br_a, br_b = self.get_unbalanced_branch_pair()
 
124
        # ensure the revision is missing.
 
125
        self.assertRaises(NoSuchRevision, br_b.get_revision, 
 
126
                          br_a.revision_history()[0])
 
127
        br_a.push_stores(br_b)
 
128
        # check that b now has all the data from a's first commit.
 
129
        rev = br_b.get_revision(br_a.revision_history()[0])
 
130
        tree = br_b.revision_tree(br_a.revision_history()[0])
 
131
        for file_id in tree:
 
132
            if tree.inventory[file_id].kind == "file":
 
133
                tree.get_file(file_id).read()
 
134
        return br_a, br_b
 
135
 
 
136
    def test_copy_branch(self):
 
137
        """Copy the stores from one branch to another"""
 
138
        br_a, br_b = self.get_balanced_branch_pair()
 
139
        commit(br_b, "silly commit")
 
140
        os.mkdir('c')
 
141
        br_c = copy_branch(br_a, 'c', basis_branch=br_b)
 
142
        self.assertEqual(br_a.revision_history(), br_c.revision_history())
 
143
 
 
144
    def test_copy_partial(self):
142
145
        """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')
 
146
        self.build_tree(['a/', 'a/one'])
 
147
        br_a = self.make_branch('a')
 
148
        br_a.working_tree().add(['one'])
 
149
        br_a.working_tree().commit('commit one', rev_id='u@d-1')
150
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'])
 
151
        br_a.working_tree().add(['two'])
 
152
        br_a.working_tree().commit('commit two', rev_id='u@d-2')
 
153
        br_b = copy_branch(br_a, 'b', revision='u@d-1')
 
154
        self.assertEqual(br_b.last_revision(), 'u@d-1')
 
155
        self.assertTrue(os.path.exists('b/one'))
 
156
        self.assertFalse(os.path.exists('b/two'))
 
157
        
 
158
    def test_record_initial_ghost_merge(self):
 
159
        """A pending merge with no revision present is still a merge."""
 
160
        branch = self.get_branch()
 
161
        branch.working_tree().add_pending_merge('non:existent@rev--ision--0--2')
 
162
        branch.working_tree().commit('pretend to merge nonexistent-revision', rev_id='first')
 
163
        rev = branch.get_revision(branch.last_revision())
 
164
        self.assertEqual(len(rev.parent_ids), 1)
226
165
        # parent_sha1s is not populated now, WTF. rbc 20051003
227
166
        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)
 
167
        self.assertEqual(rev.parent_ids[0], 'non:existent@rev--ision--0--2')
243
168
 
244
169
    def test_bad_revision(self):
245
 
        self.assertRaises(errors.InvalidRevisionId,
246
 
                          self.get_branch().repository.get_revision,
247
 
                          None)
 
170
        self.assertRaises(errors.InvalidRevisionId, self.get_branch().get_revision, None)
248
171
 
249
172
# TODO 20051003 RBC:
250
 
# compare the gpg-to-sign info for a commit with a ghost and
 
173
# compare the gpg-to-sign info for a commit with a ghost and 
251
174
#     an identical tree without a ghost
252
175
# fetch missing should rewrite the TOC of weaves to list newly available parents.
 
176
        
 
177
    def test_pending_merges(self):
 
178
        """Tracking pending-merged revisions."""
 
179
        b = self.get_branch()
 
180
        wt = b.working_tree()
 
181
        self.assertEquals(wt.pending_merges(), [])
 
182
        wt.add_pending_merge('foo@azkhazan-123123-abcabc')
 
183
        self.assertEquals(wt.pending_merges(), ['foo@azkhazan-123123-abcabc'])
 
184
        wt.add_pending_merge('foo@azkhazan-123123-abcabc')
 
185
        self.assertEquals(wt.pending_merges(), ['foo@azkhazan-123123-abcabc'])
 
186
        wt.add_pending_merge('wibble@fofof--20050401--1928390812')
 
187
        self.assertEquals(wt.pending_merges(),
 
188
                          ['foo@azkhazan-123123-abcabc',
 
189
                           'wibble@fofof--20050401--1928390812'])
 
190
        b.working_tree().commit("commit from base with two merges")
 
191
        rev = b.get_revision(b.revision_history()[0])
 
192
        self.assertEquals(len(rev.parent_ids), 2)
 
193
        self.assertEquals(rev.parent_ids[0],
 
194
                          'foo@azkhazan-123123-abcabc')
 
195
        self.assertEquals(rev.parent_ids[1],
 
196
                           'wibble@fofof--20050401--1928390812')
 
197
        # list should be cleared when we do a commit
 
198
        self.assertEquals(wt.pending_merges(), [])
253
199
 
254
200
    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')
 
201
        branch = self.get_branch()
 
202
        branch.working_tree().commit("base", allow_pointless=True, rev_id='A')
258
203
        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'))
 
204
        branch.sign_revision('A', bzrlib.gpg.LoopbackGPGStrategy(None))
 
205
        self.assertEqual(Testament.from_revision(branch, 'A').as_short_text(),
 
206
                         branch.revision_store.get('A', 'sig').read())
270
207
 
271
208
    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)
 
209
        branch = self.get_branch()
 
210
        branch.store_revision_signature(bzrlib.gpg.LoopbackGPGStrategy(None),
 
211
                                        'FOO', 'A')
 
212
        self.assertEqual('FOO', branch.revision_store.get('A', 'sig').read())
 
213
 
 
214
    def test__relcontrolfilename(self):
 
215
        self.assertEqual('.bzr/%25', self.get_branch()._rel_controlfilename('%'))
 
216
        
 
217
    def test__relcontrolfilename_empty(self):
 
218
        self.assertEqual('.bzr', self.get_branch()._rel_controlfilename(''))
341
219
 
342
220
    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())
 
221
        """Branch nicknames"""
 
222
        os.mkdir('bzr.dev')
350
223
        branch = self.make_branch('bzr.dev')
351
 
        # The nick will be 'bzr.dev', because there is no explicit nick set.
352
224
        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'))
 
225
        os.rename('bzr.dev', 'bzr.ab')
 
226
        branch = Branch.open('bzr.ab')
357
227
        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.
 
228
        branch.nick = "Aaron's branch"
 
229
        branch.nick = "Aaron's branch"
 
230
        self.failUnless(os.path.exists(branch.controlfilename("branch.conf")))
365
231
        self.assertEqual(branch.nick, "Aaron's branch")
366
 
        t.move('bzr.ab', 'integration')
367
 
        branch = _mod_branch.Branch.open(self.get_url('integration'))
 
232
        os.rename('bzr.ab', 'integration')
 
233
        branch = Branch.open('integration')
368
234
        self.assertEqual(branch.nick, "Aaron's branch")
369
235
        branch.nick = u"\u1234"
370
236
        self.assertEqual(branch.nick, u"\u1234")
371
237
 
372
238
    def test_commit_nicks(self):
373
239
        """Nicknames are committed to the revision"""
374
 
        wt = self.make_branch_and_tree('bzr.dev')
375
 
        branch = wt.branch
 
240
        os.mkdir('bzr.dev')
 
241
        branch = self.get_branch()
376
242
        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"],
 
243
        branch.working_tree().commit('My commit respect da nick.')
 
244
        committed = branch.get_revision(branch.last_revision())
 
245
        self.assertEqual(committed.properties["branch-nick"], 
380
246
                         "My happy branch")
381
247
 
382
 
    def test_create_open_branch_uses_repository(self):
383
 
        try:
384
 
            repo = self.make_repository('.', shared=True)
385
 
        except errors.IncompatibleFormat:
386
 
            return
387
 
        child_transport = repo.bzrdir.root_transport.clone('child')
388
 
        child_transport.mkdir('.')
389
 
        child_dir = self.bzrdir_format.initialize_on_transport(child_transport)
390
 
        try:
391
 
            child_branch = self.branch_format.initialize(child_dir)
392
 
        except errors.UninitializableFormat:
393
 
            # branch references are not default init'able.
394
 
            return
395
 
        self.assertEqual(repo.bzrdir.root_transport.base,
396
 
                         child_branch.repository.bzrdir.root_transport.base)
397
 
        child_branch = _mod_branch.Branch.open(self.get_url('child'))
398
 
        self.assertEqual(repo.bzrdir.root_transport.base,
399
 
                         child_branch.repository.bzrdir.root_transport.base)
400
 
 
401
 
    def test_format_description(self):
402
 
        tree = self.make_branch_and_tree('tree')
403
 
        text = tree.branch._format.get_format_description()
404
 
        self.failUnless(len(text))
405
 
 
406
 
    def test_get_commit_builder(self):
407
 
        branch = self.make_branch(".")
408
 
        branch.lock_write()
409
 
        builder = branch.get_commit_builder([])
410
 
        self.assertIsInstance(builder, repository.CommitBuilder)
411
 
        branch.repository.commit_write_group()
412
 
        branch.unlock()
413
 
 
414
 
    def test_generate_revision_history(self):
415
 
        """Create a fake revision history easily."""
416
 
        tree = self.make_branch_and_tree('.')
417
 
        rev1 = tree.commit('foo')
418
 
        orig_history = tree.branch.revision_history()
419
 
        rev2 = tree.commit('bar', allow_pointless=True)
420
 
        tree.branch.generate_revision_history(rev1)
421
 
        self.assertEqual(orig_history, tree.branch.revision_history())
422
 
 
423
 
    def test_generate_revision_history_NULL_REVISION(self):
424
 
        tree = self.make_branch_and_tree('.')
425
 
        rev1 = tree.commit('foo')
426
 
        tree.branch.generate_revision_history(revision.NULL_REVISION)
427
 
        self.assertEqual([], tree.branch.revision_history())
428
 
 
429
 
    def test_create_checkout(self):
430
 
        tree_a = self.make_branch_and_tree('a')
431
 
        branch_a = tree_a.branch
432
 
        checkout_b = branch_a.create_checkout('b')
433
 
        self.assertEqual('null:', checkout_b.last_revision())
434
 
        checkout_b.commit('rev1', rev_id='rev1')
435
 
        self.assertEqual('rev1', branch_a.last_revision())
436
 
        self.assertNotEqual(checkout_b.branch.base, branch_a.base)
437
 
 
438
 
        checkout_c = branch_a.create_checkout('c', lightweight=True)
439
 
        self.assertEqual('rev1', checkout_c.last_revision())
440
 
        checkout_c.commit('rev2', rev_id='rev2')
441
 
        self.assertEqual('rev2', branch_a.last_revision())
442
 
        self.assertEqual(checkout_c.branch.base, branch_a.base)
443
 
 
444
 
        checkout_d = branch_a.create_checkout('d', lightweight=True)
445
 
        self.assertEqual('rev2', checkout_d.last_revision())
446
 
        checkout_e = branch_a.create_checkout('e')
447
 
        self.assertEqual('rev2', checkout_e.last_revision())
448
 
 
449
 
    def test_create_anonymous_lightweight_checkout(self):
450
 
        """A lightweight checkout from a readonly branch should succeed."""
451
 
        tree_a = self.make_branch_and_tree('a')
452
 
        rev_id = tree_a.commit('put some content in the branch')
453
 
        # open the branch via a readonly transport
454
 
        source_branch = _mod_branch.Branch.open(self.get_readonly_url('a'))
455
 
        # sanity check that the test will be valid
456
 
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
457
 
            source_branch.lock_write)
458
 
        checkout = source_branch.create_checkout('c', lightweight=True)
459
 
        self.assertEqual(rev_id, checkout.last_revision())
460
 
 
461
 
    def test_create_anonymous_heavyweight_checkout(self):
462
 
        """A regular checkout from a readonly branch should succeed."""
463
 
        tree_a = self.make_branch_and_tree('a')
464
 
        rev_id = tree_a.commit('put some content in the branch')
465
 
        # open the branch via a readonly transport
466
 
        source_branch = _mod_branch.Branch.open(self.get_readonly_url('a'))
467
 
        # sanity check that the test will be valid
468
 
        self.assertRaises((errors.LockError, errors.TransportNotPossible),
469
 
            source_branch.lock_write)
470
 
        checkout = source_branch.create_checkout('c')
471
 
        self.assertEqual(rev_id, checkout.last_revision())
472
 
 
473
 
    def test_set_revision_history(self):
474
 
        tree = self.make_branch_and_tree('a')
475
 
        tree.commit('a commit', rev_id='rev1')
476
 
        br = tree.branch
477
 
        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 TestBranchFormat(per_branch.TestCaseWithBranch):
484
 
 
485
 
    def test_branch_format_network_name(self):
486
 
        br = self.make_branch('.')
487
 
        format = br._format
488
 
        network_name = format.network_name()
489
 
        self.assertIsInstance(network_name, str)
490
 
        # We want to test that the network_name matches the actual format on
491
 
        # disk. For local branches that means that using network_name as a key
492
 
        # in the registry gives back the same format. For remote branches we
493
 
        # check that the network_name of the RemoteBranchFormat we have locally
494
 
        # matches the actual format present on disk.
495
 
        if isinstance(format, remote.RemoteBranchFormat):
496
 
            br._ensure_real()
497
 
            real_branch = br._real_branch
498
 
            self.assertEqual(real_branch._format.network_name(), network_name)
499
 
        else:
500
 
            registry = _mod_branch.network_format_registry
501
 
            looked_up_format = registry.get(network_name)
502
 
            self.assertEqual(format.__class__, looked_up_format.__class__)
503
 
 
504
 
 
505
 
class ChrootedTests(per_branch.TestCaseWithBranch):
506
 
    """A support class that provides readonly urls outside the local namespace.
507
 
 
508
 
    This is done by checking if self.transport_server is a MemoryServer. if it
509
 
    is then we are chrooted already, if it is not then an HttpServer is used
510
 
    for readonly urls.
511
 
    """
512
 
 
513
 
    def setUp(self):
514
 
        super(ChrootedTests, self).setUp()
515
 
        if not self.vfs_transport_factory == MemoryServer:
516
 
            self.transport_readonly_server = HttpServer
 
248
 
 
249
class TestRemote(TestCaseWithWebserver):
517
250
 
518
251
    def test_open_containing(self):
519
 
        self.assertRaises(errors.NotBranchError,
520
 
                          _mod_branch.Branch.open_containing,
521
 
                          self.get_readonly_url(''))
522
 
        self.assertRaises(errors.NotBranchError,
523
 
                          _mod_branch.Branch.open_containing,
524
 
                          self.get_readonly_url('g/p/q'))
525
 
        branch = self.make_branch('.')
526
 
        branch, relpath = _mod_branch.Branch.open_containing(
527
 
            self.get_readonly_url(''))
 
252
        self.assertRaises(NotBranchError, Branch.open_containing,
 
253
                          self.get_remote_url(''))
 
254
        self.assertRaises(NotBranchError, Branch.open_containing,
 
255
                          self.get_remote_url('g/p/q'))
 
256
        try:
 
257
            branch = self.branch_format.initialize('.')
 
258
        except UninitializableFormat:
 
259
            raise TestSkipped("Format %s is not initializable.")
 
260
        branch, relpath = Branch.open_containing(self.get_remote_url(''))
528
261
        self.assertEqual('', relpath)
529
 
        branch, relpath = _mod_branch.Branch.open_containing(
530
 
            self.get_readonly_url('g/p/q'))
 
262
        branch, relpath = Branch.open_containing(self.get_remote_url('g/p/q'))
531
263
        self.assertEqual('g/p/q', relpath)
532
 
 
 
264
        
 
265
# TODO: rewrite this as a regular unittest, without relying on the displayed output        
 
266
#         >>> from bzrlib.commit import commit
 
267
#         >>> bzrlib.trace.silent = True
 
268
#         >>> br1 = ScratchBranch(files=['foo', 'bar'])
 
269
#         >>> br1.working_tree().add('foo')
 
270
#         >>> br1.working_tree().add('bar')
 
271
#         >>> commit(br1, "lala!", rev_id="REVISION-ID-1", verbose=False)
 
272
#         >>> br2 = ScratchBranch()
 
273
#         >>> br2.update_revisions(br1)
 
274
#         Added 2 texts.
 
275
#         Added 1 inventories.
 
276
#         Added 1 revisions.
 
277
#         >>> br2.revision_history()
 
278
#         [u'REVISION-ID-1']
 
279
#         >>> br2.update_revisions(br1)
 
280
#         Added 0 revisions.
 
281
#         >>> br1.text_store.total_size() == br2.text_store.total_size()
 
282
#         True
533
283
 
534
284
class InstrumentedTransaction(object):
535
285
 
554
304
    def unlock(self):
555
305
        self._calls.append('ul')
556
306
 
557
 
    @_mod_branch.needs_read_lock
 
307
    @needs_read_lock
558
308
    def do_with_read(self):
559
309
        return 1
560
310
 
561
 
    @_mod_branch.needs_read_lock
 
311
    @needs_read_lock
562
312
    def except_with_read(self):
563
313
        raise RuntimeError
564
314
 
565
 
    @_mod_branch.needs_write_lock
 
315
    @needs_write_lock
566
316
    def do_with_write(self):
567
317
        return 2
568
318
 
569
 
    @_mod_branch.needs_write_lock
 
319
    @needs_write_lock
570
320
    def except_with_write(self):
571
321
        raise RuntimeError
572
322
 
573
323
 
574
 
class TestDecorators(tests.TestCase):
 
324
class TestDecorators(TestCase):
575
325
 
576
326
    def test_needs_read_lock(self):
577
327
        branch = TestDecorator()
594
344
        self.assertEqual(['lw', 'ul'], branch._calls)
595
345
 
596
346
 
597
 
class TestBranchPushLocations(per_branch.TestCaseWithBranch):
 
347
class TestBranchTransaction(TestCaseWithBranch):
 
348
 
 
349
    def setUp(self):
 
350
        super(TestBranchTransaction, self).setUp()
 
351
        self.branch = None
 
352
 
 
353
    def test_default_get_transaction(self):
 
354
        """branch.get_transaction on a new branch should give a PassThrough."""
 
355
        self.failUnless(isinstance(self.get_branch().get_transaction(),
 
356
                                   transactions.PassThroughTransaction))
 
357
 
 
358
    def test__set_new_transaction(self):
 
359
        self.get_branch()._set_transaction(transactions.ReadOnlyTransaction())
 
360
 
 
361
    def test__set_over_existing_transaction_raises(self):
 
362
        self.get_branch()._set_transaction(transactions.ReadOnlyTransaction())
 
363
        self.assertRaises(errors.LockError,
 
364
                          self.get_branch()._set_transaction,
 
365
                          transactions.ReadOnlyTransaction())
 
366
 
 
367
    def test_finish_no_transaction_raises(self):
 
368
        self.assertRaises(errors.LockError, self.get_branch()._finish_transaction)
 
369
 
 
370
    def test_finish_readonly_transaction_works(self):
 
371
        self.get_branch()._set_transaction(transactions.ReadOnlyTransaction())
 
372
        self.get_branch()._finish_transaction()
 
373
        self.assertEqual(None, self.get_branch()._transaction)
 
374
 
 
375
    def test_unlock_calls_finish(self):
 
376
        self.get_branch().lock_read()
 
377
        transaction = InstrumentedTransaction()
 
378
        self.get_branch()._transaction = transaction
 
379
        self.get_branch().unlock()
 
380
        self.assertEqual(['finish'], transaction.calls)
 
381
 
 
382
    def test_lock_read_acquires_ro_transaction(self):
 
383
        self.get_branch().lock_read()
 
384
        self.failUnless(isinstance(self.get_branch().get_transaction(),
 
385
                                   transactions.ReadOnlyTransaction))
 
386
        self.get_branch().unlock()
 
387
        
 
388
    def test_lock_write_acquires_passthrough_transaction(self):
 
389
        self.get_branch().lock_write()
 
390
        # cannot use get_transaction as its magic
 
391
        self.failUnless(isinstance(self.get_branch()._transaction,
 
392
                                   transactions.PassThroughTransaction))
 
393
        self.get_branch().unlock()
 
394
 
 
395
 
 
396
class TestBranchPushLocations(TestCaseWithBranch):
598
397
 
599
398
    def test_get_push_location_unset(self):
600
399
        self.assertEqual(None, self.get_branch().get_push_location())
601
400
 
602
401
    def test_get_push_location_exact(self):
603
 
        from bzrlib.config import (locations_config_filename,
 
402
        from bzrlib.config import (branches_config_filename,
604
403
                                   ensure_config_dir_exists)
605
404
        ensure_config_dir_exists()
606
 
        fn = locations_config_filename()
607
 
        open(fn, 'wt').write(("[%s]\n"
608
 
                                  "push_location=foo\n" %
609
 
                                  self.get_branch().base[:-1]))
 
405
        fn = branches_config_filename()
 
406
        print >> open(fn, 'wt'), ("[%s]\n"
 
407
                                  "push_location=foo" %
 
408
                                  getcwd())
610
409
        self.assertEqual("foo", self.get_branch().get_push_location())
611
410
 
612
411
    def test_set_push_location(self):
613
 
        branch = self.get_branch()
614
 
        branch.set_push_location('foo')
615
 
        self.assertEqual('foo', branch.get_push_location())
616
 
 
617
 
 
618
 
class TestChildSubmitFormats(per_branch.TestCaseWithBranch):
619
 
 
620
 
    def test_get_child_submit_format_default(self):
621
 
        self.assertEqual(None, self.get_branch().get_child_submit_format())
622
 
 
623
 
    def test_get_child_submit_format(self):
624
 
        branch = self.get_branch()
625
 
        branch.get_config().set_user_option('child_submit_format', '10')
626
 
        branch = self.get_branch()
627
 
        self.assertEqual('10', branch.get_child_submit_format())
628
 
 
629
 
 
630
 
class TestFormat(per_branch.TestCaseWithBranch):
 
412
        from bzrlib.config import (branches_config_filename,
 
413
                                   ensure_config_dir_exists)
 
414
        ensure_config_dir_exists()
 
415
        fn = branches_config_filename()
 
416
        self.get_branch().set_push_location('foo')
 
417
        self.assertFileEqual("[%s]\n"
 
418
                             "push_location = foo" % getcwd(),
 
419
                             fn)
 
420
 
 
421
    # TODO RBC 20051029 test getting a push location from a branch in a 
 
422
    # recursive section - that is, it appends the branch name.
 
423
 
 
424
 
 
425
class TestFormat(TestCaseWithBranch):
631
426
    """Tests for the format itself."""
632
427
 
633
 
    def test_get_reference(self):
634
 
        """get_reference on all regular branches should return None."""
635
 
        if not self.branch_format.is_supported():
636
 
            # unsupported formats are not loopback testable
637
 
            # because the default open will not open them and
638
 
            # they may not be initializable.
639
 
            return
640
 
        made_branch = self.make_branch('.')
641
 
        self.assertEqual(None,
642
 
            made_branch._format.get_reference(made_branch.bzrdir))
643
 
 
644
 
    def test_set_reference(self):
645
 
        """set_reference on all regular branches should be callable."""
646
 
        if not self.branch_format.is_supported():
647
 
            # unsupported formats are not loopback testable
648
 
            # because the default open will not open them and
649
 
            # they may not be initializable.
650
 
            return
651
 
        this_branch = self.make_branch('this')
652
 
        other_branch = self.make_branch('other')
653
 
        try:
654
 
            this_branch._format.set_reference(this_branch.bzrdir, other_branch)
655
 
        except NotImplementedError:
656
 
            # that's ok
657
 
            pass
658
 
        else:
659
 
            ref = this_branch._format.get_reference(this_branch.bzrdir)
660
 
            self.assertEqual(ref, other_branch.base)
661
 
 
662
428
    def test_format_initialize_find_open(self):
663
429
        # loopback test to check the current format initializes to itself.
664
430
        if not self.branch_format.is_supported():
667
433
            # they may not be initializable.
668
434
            return
669
435
        # supported formats must be able to init and open
670
 
        t = transport.get_transport(self.get_url())
671
 
        readonly_t = transport.get_transport(self.get_readonly_url())
672
 
        made_branch = self.make_branch('.')
673
 
        self.failUnless(isinstance(made_branch, _mod_branch.Branch))
674
 
 
675
 
        # find it via bzrdir opening:
676
 
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
677
 
        direct_opened_branch = opened_control.open_branch()
678
 
        self.assertEqual(direct_opened_branch.__class__, made_branch.__class__)
679
 
        self.assertEqual(opened_control, direct_opened_branch.bzrdir)
680
 
        self.failUnless(isinstance(direct_opened_branch._format,
681
 
                        self.branch_format.__class__))
682
 
 
683
 
        # find it via Branch.open
684
 
        opened_branch = _mod_branch.Branch.open(readonly_t.base)
685
 
        self.failUnless(isinstance(opened_branch, made_branch.__class__))
686
 
        self.assertEqual(made_branch._format.__class__,
687
 
                         opened_branch._format.__class__)
688
 
        # if it has a unique id string, can we probe for it ?
689
 
        try:
690
 
            self.branch_format.get_format_string()
691
 
        except NotImplementedError:
692
 
            return
 
436
        t = get_transport('.')
 
437
        made_branch = self.branch_format.initialize(t.base)
 
438
        self.failUnless(isinstance(made_branch, branch.Branch))
693
439
        self.assertEqual(self.branch_format,
694
 
                         opened_control.find_branch_format())
695
 
 
696
 
 
697
 
class TestBound(per_branch.TestCaseWithBranch):
698
 
 
699
 
    def test_bind_unbind(self):
700
 
        branch = self.make_branch('1')
701
 
        branch2 = self.make_branch('2')
702
 
        try:
703
 
            branch.bind(branch2)
704
 
        except errors.UpgradeRequired:
705
 
            raise tests.TestNotApplicable('Format does not support binding')
706
 
        self.assertTrue(branch.unbind())
707
 
        self.assertFalse(branch.unbind())
708
 
        self.assertIs(None, branch.get_bound_location())
709
 
 
710
 
    def test_old_bound_location(self):
711
 
        branch = self.make_branch('branch1')
712
 
        try:
713
 
            self.assertIs(None, branch.get_old_bound_location())
714
 
        except errors.UpgradeRequired:
715
 
            raise tests.TestNotApplicable(
716
 
                    'Format does not store old bound locations')
717
 
        branch2 = self.make_branch('branch2')
718
 
        branch.bind(branch2)
719
 
        self.assertIs(None, branch.get_old_bound_location())
720
 
        branch.unbind()
721
 
        self.assertContainsRe(branch.get_old_bound_location(), '\/branch2\/$')
722
 
 
723
 
    def test_bind_diverged(self):
724
 
        tree_a = self.make_branch_and_tree('tree_a')
725
 
        tree_a.commit('rev1a')
726
 
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
727
 
        tree_a.commit('rev2a')
728
 
        tree_b.commit('rev2b')
729
 
        try:
730
 
            tree_b.branch.bind(tree_a.branch)
731
 
        except errors.UpgradeRequired:
732
 
            raise tests.TestNotApplicable('Format does not support binding')
733
 
 
734
 
 
735
 
class TestStrict(per_branch.TestCaseWithBranch):
736
 
 
737
 
    def test_strict_history(self):
738
 
        tree1 = self.make_branch_and_tree('tree1')
739
 
        try:
740
 
            tree1.branch.set_append_revisions_only(True)
741
 
        except errors.UpgradeRequired:
742
 
            raise tests.TestSkipped('Format does not support strict history')
743
 
        tree1.commit('empty commit')
744
 
        tree2 = tree1.bzrdir.sprout('tree2').open_workingtree()
745
 
        tree2.commit('empty commit 2')
746
 
        tree1.pull(tree2.branch)
747
 
        tree1.commit('empty commit 3')
748
 
        tree2.commit('empty commit 4')
749
 
        self.assertRaises(errors.DivergedBranches, tree1.pull, tree2.branch)
750
 
        tree2.merge_from_branch(tree1.branch)
751
 
        tree2.commit('empty commit 5')
752
 
        self.assertRaises(errors.AppendRevisionsOnlyViolation, tree1.pull,
753
 
                          tree2.branch)
754
 
        tree3 = tree1.bzrdir.sprout('tree3').open_workingtree()
755
 
        tree3.merge_from_branch(tree2.branch)
756
 
        tree3.commit('empty commit 6')
757
 
        tree2.pull(tree3.branch)
758
 
 
759
 
 
760
 
class TestIgnoreFallbacksParameter(per_branch.TestCaseWithBranch):
761
 
 
762
 
    def make_branch_with_fallback(self):
763
 
        fallback = self.make_branch('fallback')
764
 
        if not fallback._format.supports_stacking():
765
 
            raise tests.TestNotApplicable("format does not support stacking")
766
 
        stacked = self.make_branch('stacked')
767
 
        stacked.set_stacked_on_url(fallback.base)
768
 
        return stacked
769
 
 
770
 
    def test_fallbacks_not_opened(self):
771
 
        stacked = self.make_branch_with_fallback()
772
 
        self.get_transport('').rename('fallback', 'moved')
773
 
        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=True)
774
 
        self.assertEqual([], reopened.repository._fallback_repositories)
775
 
 
776
 
    def test_fallbacks_are_opened(self):
777
 
        stacked = self.make_branch_with_fallback()
778
 
        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=False)
779
 
        self.assertLength(1, reopened.repository._fallback_repositories)
780
 
 
781
 
 
782
 
class TestReferenceLocation(per_branch.TestCaseWithBranch):
783
 
 
784
 
    def test_reference_parent(self):
785
 
        tree = self.make_branch_and_tree('tree')
786
 
        subtree = self.make_branch_and_tree('tree/subtree')
787
 
        subtree.set_root_id('subtree-id')
788
 
        try:
789
 
            tree.add_reference(subtree)
790
 
        except errors.UnsupportedOperation:
791
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
792
 
        reference_parent = tree.branch.reference_parent('subtree-id',
793
 
                                                        'subtree')
794
 
        self.assertEqual(subtree.branch.base, reference_parent.base)
795
 
 
796
 
    def test_reference_parent_accepts_possible_transports(self):
797
 
        tree = self.make_branch_and_tree('tree')
798
 
        subtree = self.make_branch_and_tree('tree/subtree')
799
 
        subtree.set_root_id('subtree-id')
800
 
        try:
801
 
            tree.add_reference(subtree)
802
 
        except errors.UnsupportedOperation:
803
 
            raise tests.TestNotApplicable('Tree cannot hold references.')
804
 
        reference_parent = tree.branch.reference_parent('subtree-id',
805
 
            'subtree', possible_transports=[subtree.bzrdir.root_transport])
806
 
 
807
 
    def test_get_reference_info(self):
808
 
        branch = self.make_branch('branch')
809
 
        try:
810
 
            path, loc = branch.get_reference_info('file-id')
811
 
        except errors.UnsupportedOperation:
812
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
813
 
        self.assertIs(None, path)
814
 
        self.assertIs(None, loc)
815
 
 
816
 
    def test_set_reference_info(self):
817
 
        branch = self.make_branch('branch')
818
 
        try:
819
 
            branch.set_reference_info('file-id', 'path/to/location',
820
 
                                      'path/to/file')
821
 
        except errors.UnsupportedOperation:
822
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
823
 
 
824
 
    def test_set_get_reference_info(self):
825
 
        branch = self.make_branch('branch')
826
 
        try:
827
 
            branch.set_reference_info('file-id', 'path/to/file',
828
 
                                      'path/to/location')
829
 
        except errors.UnsupportedOperation:
830
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
831
 
        # Create a new instance to ensure storage is permanent
832
 
        branch = _mod_branch.Branch.open('branch')
833
 
        tree_path, branch_location = branch.get_reference_info('file-id')
834
 
        self.assertEqual('path/to/location', branch_location)
835
 
 
836
 
    def test_set_null_reference_info(self):
837
 
        branch = self.make_branch('branch')
838
 
        try:
839
 
            branch.set_reference_info('file-id', 'path/to/file',
840
 
                                      'path/to/location')
841
 
        except errors.UnsupportedOperation:
842
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
843
 
        branch.set_reference_info('file-id', None, None)
844
 
        tree_path, branch_location = branch.get_reference_info('file-id')
845
 
        self.assertIs(None, tree_path)
846
 
        self.assertIs(None, branch_location)
847
 
 
848
 
    def test_set_null_reference_info_when_null(self):
849
 
        branch = self.make_branch('branch')
850
 
        try:
851
 
            tree_path, branch_location = branch.get_reference_info('file-id')
852
 
        except errors.UnsupportedOperation:
853
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
854
 
        self.assertIs(None, tree_path)
855
 
        self.assertIs(None, branch_location)
856
 
        branch.set_reference_info('file-id', None, None)
857
 
 
858
 
    def test_set_null_requires_two_nones(self):
859
 
        branch = self.make_branch('branch')
860
 
        try:
861
 
            e = self.assertRaises(ValueError, branch.set_reference_info,
862
 
                                  'file-id', 'path', None)
863
 
        except errors.UnsupportedOperation:
864
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
865
 
        self.assertEqual('tree_path must be None when branch_location is'
866
 
                         ' None.', str(e))
867
 
        e = self.assertRaises(ValueError, branch.set_reference_info,
868
 
                              'file-id', None, 'location')
869
 
        self.assertEqual('branch_location must be None when tree_path is'
870
 
                         ' None.', str(e))
871
 
 
872
 
    def make_branch_with_reference(self, location, reference_location,
873
 
                                   file_id='file-id'):
874
 
        branch = self.make_branch(location)
875
 
        try:
876
 
            branch.set_reference_info(file_id, 'path/to/file',
877
 
                                      reference_location)
878
 
        except errors.UnsupportedOperation:
879
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
880
 
        return branch
881
 
 
882
 
    def test_reference_parent_from_reference_info_(self):
883
 
        referenced_branch = self.make_branch('reference_branch')
884
 
        branch = self.make_branch_with_reference('branch',
885
 
                                                 referenced_branch.base)
886
 
        parent = branch.reference_parent('file-id', 'path/to/file')
887
 
        self.assertEqual(parent.base, referenced_branch.base)
888
 
 
889
 
    def test_branch_relative_reference_location(self):
890
 
        branch = self.make_branch('branch')
891
 
        try:
892
 
            branch.set_reference_info('file-id', 'path/to/file',
893
 
            '../reference_branch')
894
 
        except errors.UnsupportedOperation:
895
 
            raise tests.TestNotApplicable('Branch cannot hold references.')
896
 
        referenced_branch = self.make_branch('reference_branch')
897
 
        parent = branch.reference_parent('file-id', 'path/to/file')
898
 
        self.assertEqual(parent.base, referenced_branch.base)
899
 
 
900
 
    def test_sprout_copies_reference_location(self):
901
 
        branch = self.make_branch_with_reference('branch', '../reference')
902
 
        new_branch = branch.bzrdir.sprout('new-branch').open_branch()
903
 
        self.assertEqual('../reference',
904
 
                         new_branch.get_reference_info('file-id')[1])
905
 
 
906
 
    def test_clone_copies_reference_location(self):
907
 
        branch = self.make_branch_with_reference('branch', '../reference')
908
 
        new_branch = branch.bzrdir.clone('new-branch').open_branch()
909
 
        self.assertEqual('../reference',
910
 
                         new_branch.get_reference_info('file-id')[1])
911
 
 
912
 
    def test_copied_locations_are_rebased(self):
913
 
        branch = self.make_branch_with_reference('branch', 'reference')
914
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
915
 
        self.assertEqual('../reference',
916
 
                         new_branch.get_reference_info('file-id')[1])
917
 
 
918
 
    def test_update_references_retains_old_references(self):
919
 
        branch = self.make_branch_with_reference('branch', 'reference')
920
 
        new_branch = self.make_branch_with_reference(
921
 
            'new_branch', 'reference', 'file-id2')
922
 
        new_branch.update_references(branch)
923
 
        self.assertEqual('reference',
924
 
                         branch.get_reference_info('file-id')[1])
925
 
 
926
 
    def test_update_references_retains_known_references(self):
927
 
        branch = self.make_branch_with_reference('branch', 'reference')
928
 
        new_branch = self.make_branch_with_reference(
929
 
            'new_branch', 'reference2')
930
 
        new_branch.update_references(branch)
931
 
        self.assertEqual('reference',
932
 
                         branch.get_reference_info('file-id')[1])
933
 
 
934
 
    def test_update_references_skips_known_references(self):
935
 
        branch = self.make_branch_with_reference('branch', 'reference')
936
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
937
 
        new_branch.set_reference_info('file-id', '../foo', '../foo')
938
 
        new_branch.update_references(branch)
939
 
        self.assertEqual('reference',
940
 
                         branch.get_reference_info('file-id')[1])
941
 
 
942
 
    def test_pull_updates_references(self):
943
 
        branch = self.make_branch_with_reference('branch', 'reference')
944
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
945
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
946
 
        branch.pull(new_branch)
947
 
        self.assertEqual('foo',
948
 
                         branch.get_reference_info('file-id2')[1])
949
 
 
950
 
    def test_push_updates_references(self):
951
 
        branch = self.make_branch_with_reference('branch', 'reference')
952
 
        new_branch = branch.bzrdir.sprout('branch/new-branch').open_branch()
953
 
        new_branch.set_reference_info('file-id2', '../foo', '../foo')
954
 
        new_branch.push(branch)
955
 
        self.assertEqual('foo',
956
 
                         branch.get_reference_info('file-id2')[1])
957
 
 
958
 
    def test_merge_updates_references(self):
959
 
        branch = self.make_branch_with_reference('branch', 'reference')
960
 
        tree = self.make_branch_and_tree('tree')
961
 
        tree.commit('foo')
962
 
        branch.pull(tree.branch)
963
 
        checkout = branch.create_checkout('checkout', lightweight=True)
964
 
        checkout.commit('bar')
965
 
        tree.lock_write()
966
 
        self.addCleanup(tree.unlock)
967
 
        merger = merge.Merger.from_revision_ids(None, tree,
968
 
                                                branch.last_revision(),
969
 
                                                other_branch=branch)
970
 
        merger.merge_type = merge.Merge3Merger
971
 
        merger.do_merge()
972
 
        self.assertEqual('../branch/reference',
973
 
                         tree.branch.get_reference_info('file-id')[1])
 
440
                         branch.BzrBranchFormat.find_format(t))
 
441
        direct_opened_branch = self.branch_format.open(t)
 
442
        opened_branch = branch.Branch.open(t.base)
 
443
        self.assertEqual(made_branch._branch_format,
 
444
                         opened_branch._branch_format)
 
445
        self.assertEqual(direct_opened_branch._branch_format,
 
446
                         opened_branch._branch_format)
 
447
        self.failUnless(isinstance(opened_branch, branch.Branch))
 
448
 
 
449
    def test_open_not_branch(self):
 
450
        self.assertRaises(NoSuchFile,
 
451
                          self.branch_format.open,
 
452
                          get_transport('.'))