/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2017-11-11 13:10:32 UTC
  • mto: This revision was merged to the branch mainline in revision 6804.
  • Revision ID: jelmer@jelmer.uk-20171111131032-31lgi8qmvlz8363d
Fix typos.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006-2013, 2016 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the BzrDir facility and any format specific tests.
 
18
 
 
19
For interface contract tests, see tests/per_bzr_dir.
 
20
"""
 
21
 
 
22
import os
 
23
import subprocess
 
24
import sys
 
25
 
 
26
from .. import (
 
27
    branch,
 
28
    bzr,
 
29
    config,
 
30
    controldir,
 
31
    errors,
 
32
    help_topics,
 
33
    lock,
 
34
    repository,
 
35
    revision as _mod_revision,
 
36
    osutils,
 
37
    transport as _mod_transport,
 
38
    urlutils,
 
39
    win32utils,
 
40
    )
 
41
from ..bzr import (
 
42
    branch as bzrbranch,
 
43
    bzrdir,
 
44
    remote,
 
45
    workingtree_3,
 
46
    workingtree_4,
 
47
    )
 
48
import breezy.branch
 
49
import breezy.bzr.branch
 
50
from ..bzr.fullhistory import BzrBranchFormat5
 
51
from ..errors import (
 
52
    NotBranchError,
 
53
    NoColocatedBranchSupport,
 
54
    UnknownFormatError,
 
55
    UnsupportedFormatError,
 
56
    )
 
57
from . import (
 
58
    TestCase,
 
59
    TestCaseWithMemoryTransport,
 
60
    TestCaseWithTransport,
 
61
    TestSkipped,
 
62
    )
 
63
from . import(
 
64
    http_server,
 
65
    http_utils,
 
66
    )
 
67
from ..transport import (
 
68
    memory,
 
69
    pathfilter,
 
70
    )
 
71
from ..transport.http._urllib import HttpTransport_urllib
 
72
from ..transport.nosmart import NoSmartTransportDecorator
 
73
from ..transport.readonly import ReadonlyTransportDecorator
 
74
from ..bzr import knitrepo, knitpack_repo
 
75
 
 
76
 
 
77
class TestDefaultFormat(TestCase):
 
78
 
 
79
    def test_get_set_default_format(self):
 
80
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
81
        # default is BzrDirMetaFormat1
 
82
        self.assertIsInstance(old_format, bzrdir.BzrDirMetaFormat1)
 
83
        controldir.ControlDirFormat._set_default_format(SampleBzrDirFormat())
 
84
        # creating a bzr dir should now create an instrumented dir.
 
85
        try:
 
86
            result = bzrdir.BzrDir.create('memory:///')
 
87
            self.assertIsInstance(result, SampleBzrDir)
 
88
        finally:
 
89
            controldir.ControlDirFormat._set_default_format(old_format)
 
90
        self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
 
91
 
 
92
 
 
93
class DeprecatedBzrDirFormat(bzrdir.BzrDirFormat):
 
94
    """A deprecated bzr dir format."""
 
95
 
 
96
 
 
97
class TestFormatRegistry(TestCase):
 
98
 
 
99
    def make_format_registry(self):
 
100
        my_format_registry = controldir.ControlDirFormatRegistry()
 
101
        my_format_registry.register('deprecated', DeprecatedBzrDirFormat,
 
102
            'Some format.  Slower and unawesome and deprecated.',
 
103
            deprecated=True)
 
104
        my_format_registry.register_lazy('lazy', 'breezy.tests.test_bzrdir',
 
105
            'DeprecatedBzrDirFormat', 'Format registered lazily',
 
106
            deprecated=True)
 
107
        bzr.register_metadir(my_format_registry, 'knit',
 
108
            'breezy.bzr.knitrepo.RepositoryFormatKnit1',
 
109
            'Format using knits',
 
110
            )
 
111
        my_format_registry.set_default('knit')
 
112
        bzr.register_metadir(my_format_registry,
 
113
            'branch6',
 
114
            'breezy.bzr.knitrepo.RepositoryFormatKnit3',
 
115
            'Experimental successor to knit.  Use at your own risk.',
 
116
            branch_format='breezy.bzr.branch.BzrBranchFormat6',
 
117
            experimental=True)
 
118
        bzr.register_metadir(my_format_registry,
 
119
            'hidden format',
 
120
            'breezy.bzr.knitrepo.RepositoryFormatKnit3',
 
121
            'Experimental successor to knit.  Use at your own risk.',
 
122
            branch_format='breezy.bzr.branch.BzrBranchFormat6', hidden=True)
 
123
        my_format_registry.register('hiddendeprecated', DeprecatedBzrDirFormat,
 
124
            'Old format.  Slower and does not support things. ', hidden=True)
 
125
        my_format_registry.register_lazy('hiddenlazy', 'breezy.tests.test_bzrdir',
 
126
            'DeprecatedBzrDirFormat', 'Format registered lazily',
 
127
            deprecated=True, hidden=True)
 
128
        return my_format_registry
 
129
 
 
130
    def test_format_registry(self):
 
131
        my_format_registry = self.make_format_registry()
 
132
        my_bzrdir = my_format_registry.make_controldir('lazy')
 
133
        self.assertIsInstance(my_bzrdir, DeprecatedBzrDirFormat)
 
134
        my_bzrdir = my_format_registry.make_controldir('deprecated')
 
135
        self.assertIsInstance(my_bzrdir, DeprecatedBzrDirFormat)
 
136
        my_bzrdir = my_format_registry.make_controldir('default')
 
137
        self.assertIsInstance(my_bzrdir.repository_format,
 
138
            knitrepo.RepositoryFormatKnit1)
 
139
        my_bzrdir = my_format_registry.make_controldir('knit')
 
140
        self.assertIsInstance(my_bzrdir.repository_format,
 
141
            knitrepo.RepositoryFormatKnit1)
 
142
        my_bzrdir = my_format_registry.make_controldir('branch6')
 
143
        self.assertIsInstance(my_bzrdir.get_branch_format(),
 
144
                              breezy.bzr.branch.BzrBranchFormat6)
 
145
 
 
146
    def test_get_help(self):
 
147
        my_format_registry = self.make_format_registry()
 
148
        self.assertEqual('Format registered lazily',
 
149
                         my_format_registry.get_help('lazy'))
 
150
        self.assertEqual('Format using knits',
 
151
                         my_format_registry.get_help('knit'))
 
152
        self.assertEqual('Format using knits',
 
153
                         my_format_registry.get_help('default'))
 
154
        self.assertEqual('Some format.  Slower and unawesome and deprecated.',
 
155
                         my_format_registry.get_help('deprecated'))
 
156
 
 
157
    def test_help_topic(self):
 
158
        topics = help_topics.HelpTopicRegistry()
 
159
        registry = self.make_format_registry()
 
160
        topics.register('current-formats', registry.help_topic,
 
161
                        'Current formats')
 
162
        topics.register('other-formats', registry.help_topic,
 
163
                        'Other formats')
 
164
        new = topics.get_detail('current-formats')
 
165
        rest = topics.get_detail('other-formats')
 
166
        experimental, deprecated = rest.split('Deprecated formats')
 
167
        self.assertContainsRe(new, 'formats-help')
 
168
        self.assertContainsRe(new,
 
169
                ':knit:\n    \\(native\\) \\(default\\) Format using knits\n')
 
170
        self.assertContainsRe(experimental,
 
171
                ':branch6:\n    \\(native\\) Experimental successor to knit')
 
172
        self.assertContainsRe(deprecated,
 
173
                ':lazy:\n    \\(native\\) Format registered lazily\n')
 
174
        self.assertNotContainsRe(new, 'hidden')
 
175
 
 
176
    def test_set_default_repository(self):
 
177
        default_factory = controldir.format_registry.get('default')
 
178
        old_default = [k for k, v in controldir.format_registry.iteritems()
 
179
                       if v == default_factory and k != 'default'][0]
 
180
        controldir.format_registry.set_default_repository('dirstate-with-subtree')
 
181
        try:
 
182
            self.assertIs(controldir.format_registry.get('dirstate-with-subtree'),
 
183
                          controldir.format_registry.get('default'))
 
184
            self.assertIs(
 
185
                repository.format_registry.get_default().__class__,
 
186
                knitrepo.RepositoryFormatKnit3)
 
187
        finally:
 
188
            controldir.format_registry.set_default_repository(old_default)
 
189
 
 
190
    def test_aliases(self):
 
191
        a_registry = controldir.ControlDirFormatRegistry()
 
192
        a_registry.register('deprecated', DeprecatedBzrDirFormat,
 
193
            'Old format.  Slower and does not support stuff',
 
194
            deprecated=True)
 
195
        a_registry.register('deprecatedalias', DeprecatedBzrDirFormat,
 
196
            'Old format.  Slower and does not support stuff',
 
197
            deprecated=True, alias=True)
 
198
        self.assertEqual(frozenset(['deprecatedalias']), a_registry.aliases())
 
199
 
 
200
 
 
201
class SampleBranch(breezy.branch.Branch):
 
202
    """A dummy branch for guess what, dummy use."""
 
203
 
 
204
    def __init__(self, dir):
 
205
        self.controldir = dir
 
206
 
 
207
 
 
208
class SampleRepository(breezy.repository.Repository):
 
209
    """A dummy repo."""
 
210
 
 
211
    def __init__(self, dir):
 
212
        self.controldir = dir
 
213
 
 
214
 
 
215
class SampleBzrDir(bzrdir.BzrDir):
 
216
    """A sample BzrDir implementation to allow testing static methods."""
 
217
 
 
218
    def create_repository(self, shared=False):
 
219
        """See ControlDir.create_repository."""
 
220
        return "A repository"
 
221
 
 
222
    def open_repository(self):
 
223
        """See ControlDir.open_repository."""
 
224
        return SampleRepository(self)
 
225
 
 
226
    def create_branch(self, name=None):
 
227
        """See ControlDir.create_branch."""
 
228
        if name is not None:
 
229
            raise NoColocatedBranchSupport(self)
 
230
        return SampleBranch(self)
 
231
 
 
232
    def create_workingtree(self):
 
233
        """See ControlDir.create_workingtree."""
 
234
        return "A tree"
 
235
 
 
236
 
 
237
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
 
238
    """A sample format
 
239
 
 
240
    this format is initializable, unsupported to aid in testing the
 
241
    open and open_downlevel routines.
 
242
    """
 
243
 
 
244
    def get_format_string(self):
 
245
        """See BzrDirFormat.get_format_string()."""
 
246
        return "Sample .bzr dir format."
 
247
 
 
248
    def initialize_on_transport(self, t):
 
249
        """Create a bzr dir."""
 
250
        t.mkdir('.bzr')
 
251
        t.put_bytes('.bzr/branch-format', self.get_format_string())
 
252
        return SampleBzrDir(t, self)
 
253
 
 
254
    def is_supported(self):
 
255
        return False
 
256
 
 
257
    def open(self, transport, _found=None):
 
258
        return "opened branch."
 
259
 
 
260
    @classmethod
 
261
    def from_string(cls, format_string):
 
262
        return cls()
 
263
 
 
264
 
 
265
class BzrDirFormatTest1(bzrdir.BzrDirMetaFormat1):
 
266
 
 
267
    @staticmethod
 
268
    def get_format_string():
 
269
        return "Test format 1"
 
270
 
 
271
 
 
272
class BzrDirFormatTest2(bzrdir.BzrDirMetaFormat1):
 
273
 
 
274
    @staticmethod
 
275
    def get_format_string():
 
276
        return "Test format 2"
 
277
 
 
278
 
 
279
class TestBzrDirFormat(TestCaseWithTransport):
 
280
    """Tests for the BzrDirFormat facility."""
 
281
 
 
282
    def test_find_format(self):
 
283
        # is the right format object found for a branch?
 
284
        # create a branch with a few known format objects.
 
285
        bzr.BzrProber.formats.register(BzrDirFormatTest1.get_format_string(),
 
286
            BzrDirFormatTest1())
 
287
        self.addCleanup(bzr.BzrProber.formats.remove,
 
288
            BzrDirFormatTest1.get_format_string())
 
289
        bzr.BzrProber.formats.register(BzrDirFormatTest2.get_format_string(),
 
290
            BzrDirFormatTest2())
 
291
        self.addCleanup(bzr.BzrProber.formats.remove,
 
292
            BzrDirFormatTest2.get_format_string())
 
293
        t = self.get_transport()
 
294
        self.build_tree(["foo/", "bar/"], transport=t)
 
295
        def check_format(format, url):
 
296
            format.initialize(url)
 
297
            t = _mod_transport.get_transport_from_path(url)
 
298
            found_format = bzrdir.BzrDirFormat.find_format(t)
 
299
            self.assertIsInstance(found_format, format.__class__)
 
300
        check_format(BzrDirFormatTest1(), "foo")
 
301
        check_format(BzrDirFormatTest2(), "bar")
 
302
 
 
303
    def test_find_format_nothing_there(self):
 
304
        self.assertRaises(NotBranchError,
 
305
                          bzrdir.BzrDirFormat.find_format,
 
306
                          _mod_transport.get_transport_from_path('.'))
 
307
 
 
308
    def test_find_format_unknown_format(self):
 
309
        t = self.get_transport()
 
310
        t.mkdir('.bzr')
 
311
        t.put_bytes('.bzr/branch-format', '')
 
312
        self.assertRaises(UnknownFormatError,
 
313
                          bzrdir.BzrDirFormat.find_format,
 
314
                          _mod_transport.get_transport_from_path('.'))
 
315
 
 
316
    def test_register_unregister_format(self):
 
317
        format = SampleBzrDirFormat()
 
318
        url = self.get_url()
 
319
        # make a bzrdir
 
320
        format.initialize(url)
 
321
        # register a format for it.
 
322
        bzr.BzrProber.formats.register(format.get_format_string(), format)
 
323
        # which bzrdir.Open will refuse (not supported)
 
324
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
 
325
        # which bzrdir.open_containing will refuse (not supported)
 
326
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
 
327
        # but open_downlevel will work
 
328
        t = _mod_transport.get_transport_from_url(url)
 
329
        self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
 
330
        # unregister the format
 
331
        bzr.BzrProber.formats.remove(format.get_format_string())
 
332
        # now open_downlevel should fail too.
 
333
        self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
 
334
 
 
335
    def test_create_branch_and_repo_uses_default(self):
 
336
        format = SampleBzrDirFormat()
 
337
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url(),
 
338
                                                      format=format)
 
339
        self.assertTrue(isinstance(branch, SampleBranch))
 
340
 
 
341
    def test_create_branch_and_repo_under_shared(self):
 
342
        # creating a branch and repo in a shared repo uses the
 
343
        # shared repository
 
344
        format = controldir.format_registry.make_controldir('knit')
 
345
        self.make_repository('.', shared=True, format=format)
 
346
        branch = bzrdir.BzrDir.create_branch_and_repo(
 
347
            self.get_url('child'), format=format)
 
348
        self.assertRaises(errors.NoRepositoryPresent,
 
349
                          branch.controldir.open_repository)
 
350
 
 
351
    def test_create_branch_and_repo_under_shared_force_new(self):
 
352
        # creating a branch and repo in a shared repo can be forced to
 
353
        # make a new repo
 
354
        format = controldir.format_registry.make_controldir('knit')
 
355
        self.make_repository('.', shared=True, format=format)
 
356
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
 
357
                                                      force_new_repo=True,
 
358
                                                      format=format)
 
359
        branch.controldir.open_repository()
 
360
 
 
361
    def test_create_standalone_working_tree(self):
 
362
        format = SampleBzrDirFormat()
 
363
        # note this is deliberately readonly, as this failure should
 
364
        # occur before any writes.
 
365
        self.assertRaises(errors.NotLocalUrl,
 
366
                          bzrdir.BzrDir.create_standalone_workingtree,
 
367
                          self.get_readonly_url(), format=format)
 
368
        tree = bzrdir.BzrDir.create_standalone_workingtree('.',
 
369
                                                           format=format)
 
370
        self.assertEqual('A tree', tree)
 
371
 
 
372
    def test_create_standalone_working_tree_under_shared_repo(self):
 
373
        # create standalone working tree always makes a repo.
 
374
        format = controldir.format_registry.make_controldir('knit')
 
375
        self.make_repository('.', shared=True, format=format)
 
376
        # note this is deliberately readonly, as this failure should
 
377
        # occur before any writes.
 
378
        self.assertRaises(errors.NotLocalUrl,
 
379
                          bzrdir.BzrDir.create_standalone_workingtree,
 
380
                          self.get_readonly_url('child'), format=format)
 
381
        tree = bzrdir.BzrDir.create_standalone_workingtree('child',
 
382
            format=format)
 
383
        tree.controldir.open_repository()
 
384
 
 
385
    def test_create_branch_convenience(self):
 
386
        # outside a repo the default convenience output is a repo+branch_tree
 
387
        format = controldir.format_registry.make_controldir('knit')
 
388
        branch = bzrdir.BzrDir.create_branch_convenience('.', format=format)
 
389
        branch.controldir.open_workingtree()
 
390
        branch.controldir.open_repository()
 
391
 
 
392
    def test_create_branch_convenience_possible_transports(self):
 
393
        """Check that the optional 'possible_transports' is recognized"""
 
394
        format = controldir.format_registry.make_controldir('knit')
 
395
        t = self.get_transport()
 
396
        branch = bzrdir.BzrDir.create_branch_convenience(
 
397
            '.', format=format, possible_transports=[t])
 
398
        branch.controldir.open_workingtree()
 
399
        branch.controldir.open_repository()
 
400
 
 
401
    def test_create_branch_convenience_root(self):
 
402
        """Creating a branch at the root of a fs should work."""
 
403
        self.vfs_transport_factory = memory.MemoryServer
 
404
        # outside a repo the default convenience output is a repo+branch_tree
 
405
        format = controldir.format_registry.make_controldir('knit')
 
406
        branch = bzrdir.BzrDir.create_branch_convenience(self.get_url(),
 
407
                                                         format=format)
 
408
        self.assertRaises(errors.NoWorkingTree,
 
409
                          branch.controldir.open_workingtree)
 
410
        branch.controldir.open_repository()
 
411
 
 
412
    def test_create_branch_convenience_under_shared_repo(self):
 
413
        # inside a repo the default convenience output is a branch+ follow the
 
414
        # repo tree policy
 
415
        format = controldir.format_registry.make_controldir('knit')
 
416
        self.make_repository('.', shared=True, format=format)
 
417
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
418
            format=format)
 
419
        branch.controldir.open_workingtree()
 
420
        self.assertRaises(errors.NoRepositoryPresent,
 
421
                          branch.controldir.open_repository)
 
422
 
 
423
    def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
 
424
        # inside a repo the default convenience output is a branch+ follow the
 
425
        # repo tree policy but we can override that
 
426
        format = controldir.format_registry.make_controldir('knit')
 
427
        self.make_repository('.', shared=True, format=format)
 
428
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
429
            force_new_tree=False, format=format)
 
430
        self.assertRaises(errors.NoWorkingTree,
 
431
                          branch.controldir.open_workingtree)
 
432
        self.assertRaises(errors.NoRepositoryPresent,
 
433
                          branch.controldir.open_repository)
 
434
 
 
435
    def test_create_branch_convenience_under_shared_repo_no_tree_policy(self):
 
436
        # inside a repo the default convenience output is a branch+ follow the
 
437
        # repo tree policy
 
438
        format = controldir.format_registry.make_controldir('knit')
 
439
        repo = self.make_repository('.', shared=True, format=format)
 
440
        repo.set_make_working_trees(False)
 
441
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
442
                                                         format=format)
 
443
        self.assertRaises(errors.NoWorkingTree,
 
444
                          branch.controldir.open_workingtree)
 
445
        self.assertRaises(errors.NoRepositoryPresent,
 
446
                          branch.controldir.open_repository)
 
447
 
 
448
    def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
 
449
        # inside a repo the default convenience output is a branch+ follow the
 
450
        # repo tree policy but we can override that
 
451
        format = controldir.format_registry.make_controldir('knit')
 
452
        repo = self.make_repository('.', shared=True, format=format)
 
453
        repo.set_make_working_trees(False)
 
454
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
455
            force_new_tree=True, format=format)
 
456
        branch.controldir.open_workingtree()
 
457
        self.assertRaises(errors.NoRepositoryPresent,
 
458
                          branch.controldir.open_repository)
 
459
 
 
460
    def test_create_branch_convenience_under_shared_repo_force_new_repo(self):
 
461
        # inside a repo the default convenience output is overridable to give
 
462
        # repo+branch+tree
 
463
        format = controldir.format_registry.make_controldir('knit')
 
464
        self.make_repository('.', shared=True, format=format)
 
465
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
466
            force_new_repo=True, format=format)
 
467
        branch.controldir.open_repository()
 
468
        branch.controldir.open_workingtree()
 
469
 
 
470
 
 
471
class TestRepositoryAcquisitionPolicy(TestCaseWithTransport):
 
472
 
 
473
    def test_acquire_repository_standalone(self):
 
474
        """The default acquisition policy should create a standalone branch."""
 
475
        my_bzrdir = self.make_controldir('.')
 
476
        repo_policy = my_bzrdir.determine_repository_policy()
 
477
        repo, is_new = repo_policy.acquire_repository()
 
478
        self.assertEqual(repo.controldir.root_transport.base,
 
479
                         my_bzrdir.root_transport.base)
 
480
        self.assertFalse(repo.is_shared())
 
481
 
 
482
    def test_determine_stacking_policy(self):
 
483
        parent_bzrdir = self.make_controldir('.')
 
484
        child_bzrdir = self.make_controldir('child')
 
485
        parent_bzrdir.get_config().set_default_stack_on('http://example.org')
 
486
        repo_policy = child_bzrdir.determine_repository_policy()
 
487
        self.assertEqual('http://example.org', repo_policy._stack_on)
 
488
 
 
489
    def test_determine_stacking_policy_relative(self):
 
490
        parent_bzrdir = self.make_controldir('.')
 
491
        child_bzrdir = self.make_controldir('child')
 
492
        parent_bzrdir.get_config().set_default_stack_on('child2')
 
493
        repo_policy = child_bzrdir.determine_repository_policy()
 
494
        self.assertEqual('child2', repo_policy._stack_on)
 
495
        self.assertEqual(parent_bzrdir.root_transport.base,
 
496
                         repo_policy._stack_on_pwd)
 
497
 
 
498
    def prepare_default_stacking(self, child_format='1.6'):
 
499
        parent_bzrdir = self.make_controldir('.')
 
500
        child_branch = self.make_branch('child', format=child_format)
 
501
        parent_bzrdir.get_config().set_default_stack_on(child_branch.base)
 
502
        new_child_transport = parent_bzrdir.transport.clone('child2')
 
503
        return child_branch, new_child_transport
 
504
 
 
505
    def test_clone_on_transport_obeys_stacking_policy(self):
 
506
        child_branch, new_child_transport = self.prepare_default_stacking()
 
507
        new_child = child_branch.controldir.clone_on_transport(new_child_transport)
 
508
        self.assertEqual(child_branch.base,
 
509
                         new_child.open_branch().get_stacked_on_url())
 
510
 
 
511
    def test_default_stacking_with_stackable_branch_unstackable_repo(self):
 
512
        # Make stackable source branch with an unstackable repo format.
 
513
        source_bzrdir = self.make_controldir('source')
 
514
        knitpack_repo.RepositoryFormatKnitPack1().initialize(source_bzrdir)
 
515
        source_branch = breezy.bzr.branch.BzrBranchFormat7().initialize(
 
516
            source_bzrdir)
 
517
        # Make a directory with a default stacking policy
 
518
        parent_bzrdir = self.make_controldir('parent')
 
519
        stacked_on = self.make_branch('parent/stacked-on', format='pack-0.92')
 
520
        parent_bzrdir.get_config().set_default_stack_on(stacked_on.base)
 
521
        # Clone source into directory
 
522
        target = source_bzrdir.clone(self.get_url('parent/target'))
 
523
 
 
524
    def test_format_initialize_on_transport_ex_stacked_on(self):
 
525
        # trunk is a stackable format.  Note that its in the same server area
 
526
        # which is what launchpad does, but not sufficient to exercise the
 
527
        # general case.
 
528
        trunk = self.make_branch('trunk', format='1.9')
 
529
        t = self.get_transport('stacked')
 
530
        old_fmt = controldir.format_registry.make_controldir('pack-0.92')
 
531
        repo_name = old_fmt.repository_format.network_name()
 
532
        # Should end up with a 1.9 format (stackable)
 
533
        repo, control, require_stacking, repo_policy = \
 
534
            old_fmt.initialize_on_transport_ex(t,
 
535
                    repo_format_name=repo_name, stacked_on='../trunk',
 
536
                    stack_on_pwd=t.base)
 
537
        if repo is not None:
 
538
            # Repositories are open write-locked
 
539
            self.assertTrue(repo.is_write_locked())
 
540
            self.addCleanup(repo.unlock)
 
541
        else:
 
542
            repo = control.open_repository()
 
543
        self.assertIsInstance(control, bzrdir.BzrDir)
 
544
        opened = bzrdir.BzrDir.open(t.base)
 
545
        if not isinstance(old_fmt, remote.RemoteBzrDirFormat):
 
546
            self.assertEqual(control._format.network_name(),
 
547
                old_fmt.network_name())
 
548
            self.assertEqual(control._format.network_name(),
 
549
                opened._format.network_name())
 
550
        self.assertEqual(control.__class__, opened.__class__)
 
551
        self.assertLength(1, repo._fallback_repositories)
 
552
 
 
553
    def test_sprout_obeys_stacking_policy(self):
 
554
        child_branch, new_child_transport = self.prepare_default_stacking()
 
555
        new_child = child_branch.controldir.sprout(new_child_transport.base)
 
556
        self.assertEqual(child_branch.base,
 
557
                         new_child.open_branch().get_stacked_on_url())
 
558
 
 
559
    def test_clone_ignores_policy_for_unsupported_formats(self):
 
560
        child_branch, new_child_transport = self.prepare_default_stacking(
 
561
            child_format='pack-0.92')
 
562
        new_child = child_branch.controldir.clone_on_transport(new_child_transport)
 
563
        self.assertRaises(branch.UnstackableBranchFormat,
 
564
                          new_child.open_branch().get_stacked_on_url)
 
565
 
 
566
    def test_sprout_ignores_policy_for_unsupported_formats(self):
 
567
        child_branch, new_child_transport = self.prepare_default_stacking(
 
568
            child_format='pack-0.92')
 
569
        new_child = child_branch.controldir.sprout(new_child_transport.base)
 
570
        self.assertRaises(branch.UnstackableBranchFormat,
 
571
                          new_child.open_branch().get_stacked_on_url)
 
572
 
 
573
    def test_sprout_upgrades_format_if_stacked_specified(self):
 
574
        child_branch, new_child_transport = self.prepare_default_stacking(
 
575
            child_format='pack-0.92')
 
576
        new_child = child_branch.controldir.sprout(new_child_transport.base,
 
577
                                               stacked=True)
 
578
        self.assertEqual(child_branch.controldir.root_transport.base,
 
579
                         new_child.open_branch().get_stacked_on_url())
 
580
        repo = new_child.open_repository()
 
581
        self.assertTrue(repo._format.supports_external_lookups)
 
582
        self.assertFalse(repo.supports_rich_root())
 
583
 
 
584
    def test_clone_on_transport_upgrades_format_if_stacked_on_specified(self):
 
585
        child_branch, new_child_transport = self.prepare_default_stacking(
 
586
            child_format='pack-0.92')
 
587
        new_child = child_branch.controldir.clone_on_transport(new_child_transport,
 
588
            stacked_on=child_branch.controldir.root_transport.base)
 
589
        self.assertEqual(child_branch.controldir.root_transport.base,
 
590
                         new_child.open_branch().get_stacked_on_url())
 
591
        repo = new_child.open_repository()
 
592
        self.assertTrue(repo._format.supports_external_lookups)
 
593
        self.assertFalse(repo.supports_rich_root())
 
594
 
 
595
    def test_sprout_upgrades_to_rich_root_format_if_needed(self):
 
596
        child_branch, new_child_transport = self.prepare_default_stacking(
 
597
            child_format='rich-root-pack')
 
598
        new_child = child_branch.controldir.sprout(new_child_transport.base,
 
599
                                               stacked=True)
 
600
        repo = new_child.open_repository()
 
601
        self.assertTrue(repo._format.supports_external_lookups)
 
602
        self.assertTrue(repo.supports_rich_root())
 
603
 
 
604
    def test_add_fallback_repo_handles_absolute_urls(self):
 
605
        stack_on = self.make_branch('stack_on', format='1.6')
 
606
        repo = self.make_repository('repo', format='1.6')
 
607
        policy = bzrdir.UseExistingRepository(repo, stack_on.base)
 
608
        policy._add_fallback(repo)
 
609
 
 
610
    def test_add_fallback_repo_handles_relative_urls(self):
 
611
        stack_on = self.make_branch('stack_on', format='1.6')
 
612
        repo = self.make_repository('repo', format='1.6')
 
613
        policy = bzrdir.UseExistingRepository(repo, '.', stack_on.base)
 
614
        policy._add_fallback(repo)
 
615
 
 
616
    def test_configure_relative_branch_stacking_url(self):
 
617
        stack_on = self.make_branch('stack_on', format='1.6')
 
618
        stacked = self.make_branch('stack_on/stacked', format='1.6')
 
619
        policy = bzrdir.UseExistingRepository(stacked.repository,
 
620
            '.', stack_on.base)
 
621
        policy.configure_branch(stacked)
 
622
        self.assertEqual('..', stacked.get_stacked_on_url())
 
623
 
 
624
    def test_relative_branch_stacking_to_absolute(self):
 
625
        stack_on = self.make_branch('stack_on', format='1.6')
 
626
        stacked = self.make_branch('stack_on/stacked', format='1.6')
 
627
        policy = bzrdir.UseExistingRepository(stacked.repository,
 
628
            '.', self.get_readonly_url('stack_on'))
 
629
        policy.configure_branch(stacked)
 
630
        self.assertEqual(self.get_readonly_url('stack_on'),
 
631
                         stacked.get_stacked_on_url())
 
632
 
 
633
 
 
634
class ChrootedTests(TestCaseWithTransport):
 
635
    """A support class that provides readonly urls outside the local namespace.
 
636
 
 
637
    This is done by checking if self.transport_server is a MemoryServer. if it
 
638
    is then we are chrooted already, if it is not then an HttpServer is used
 
639
    for readonly urls.
 
640
    """
 
641
 
 
642
    def setUp(self):
 
643
        super(ChrootedTests, self).setUp()
 
644
        if not self.vfs_transport_factory == memory.MemoryServer:
 
645
            self.transport_readonly_server = http_server.HttpServer
 
646
 
 
647
    def local_branch_path(self, branch):
 
648
         return os.path.realpath(urlutils.local_path_from_url(branch.base))
 
649
 
 
650
    def test_open_containing(self):
 
651
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
652
                          self.get_readonly_url(''))
 
653
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
654
                          self.get_readonly_url('g/p/q'))
 
655
        control = bzrdir.BzrDir.create(self.get_url())
 
656
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
 
657
        self.assertEqual('', relpath)
 
658
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
 
659
        self.assertEqual('g/p/q', relpath)
 
660
 
 
661
    def test_open_containing_tree_branch_or_repository_empty(self):
 
662
        self.assertRaises(errors.NotBranchError,
 
663
            bzrdir.BzrDir.open_containing_tree_branch_or_repository,
 
664
            self.get_readonly_url(''))
 
665
 
 
666
    def test_open_containing_tree_branch_or_repository_all(self):
 
667
        self.make_branch_and_tree('topdir')
 
668
        tree, branch, repo, relpath = \
 
669
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
670
                'topdir/foo')
 
671
        self.assertEqual(os.path.realpath('topdir'),
 
672
                         os.path.realpath(tree.basedir))
 
673
        self.assertEqual(os.path.realpath('topdir'),
 
674
                         self.local_branch_path(branch))
 
675
        self.assertEqual(
 
676
            osutils.realpath(os.path.join('topdir', '.bzr', 'repository')),
 
677
            repo.controldir.transport.local_abspath('repository'))
 
678
        self.assertEqual(relpath, 'foo')
 
679
 
 
680
    def test_open_containing_tree_branch_or_repository_no_tree(self):
 
681
        self.make_branch('branch')
 
682
        tree, branch, repo, relpath = \
 
683
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
684
                'branch/foo')
 
685
        self.assertEqual(tree, None)
 
686
        self.assertEqual(os.path.realpath('branch'),
 
687
                         self.local_branch_path(branch))
 
688
        self.assertEqual(
 
689
            osutils.realpath(os.path.join('branch', '.bzr', 'repository')),
 
690
            repo.controldir.transport.local_abspath('repository'))
 
691
        self.assertEqual(relpath, 'foo')
 
692
 
 
693
    def test_open_containing_tree_branch_or_repository_repo(self):
 
694
        self.make_repository('repo')
 
695
        tree, branch, repo, relpath = \
 
696
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
697
                'repo')
 
698
        self.assertEqual(tree, None)
 
699
        self.assertEqual(branch, None)
 
700
        self.assertEqual(
 
701
            osutils.realpath(os.path.join('repo', '.bzr', 'repository')),
 
702
            repo.controldir.transport.local_abspath('repository'))
 
703
        self.assertEqual(relpath, '')
 
704
 
 
705
    def test_open_containing_tree_branch_or_repository_shared_repo(self):
 
706
        self.make_repository('shared', shared=True)
 
707
        bzrdir.BzrDir.create_branch_convenience('shared/branch',
 
708
                                                force_new_tree=False)
 
709
        tree, branch, repo, relpath = \
 
710
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
711
                'shared/branch')
 
712
        self.assertEqual(tree, None)
 
713
        self.assertEqual(os.path.realpath('shared/branch'),
 
714
                         self.local_branch_path(branch))
 
715
        self.assertEqual(
 
716
            osutils.realpath(os.path.join('shared', '.bzr', 'repository')),
 
717
            repo.controldir.transport.local_abspath('repository'))
 
718
        self.assertEqual(relpath, '')
 
719
 
 
720
    def test_open_containing_tree_branch_or_repository_branch_subdir(self):
 
721
        self.make_branch_and_tree('foo')
 
722
        self.build_tree(['foo/bar/'])
 
723
        tree, branch, repo, relpath = \
 
724
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
725
                'foo/bar')
 
726
        self.assertEqual(os.path.realpath('foo'),
 
727
                         os.path.realpath(tree.basedir))
 
728
        self.assertEqual(os.path.realpath('foo'),
 
729
                         self.local_branch_path(branch))
 
730
        self.assertEqual(
 
731
            osutils.realpath(os.path.join('foo', '.bzr', 'repository')),
 
732
            repo.controldir.transport.local_abspath('repository'))
 
733
        self.assertEqual(relpath, 'bar')
 
734
 
 
735
    def test_open_containing_tree_branch_or_repository_repo_subdir(self):
 
736
        self.make_repository('bar')
 
737
        self.build_tree(['bar/baz/'])
 
738
        tree, branch, repo, relpath = \
 
739
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
740
                'bar/baz')
 
741
        self.assertEqual(tree, None)
 
742
        self.assertEqual(branch, None)
 
743
        self.assertEqual(
 
744
            osutils.realpath(os.path.join('bar', '.bzr', 'repository')),
 
745
            repo.controldir.transport.local_abspath('repository'))
 
746
        self.assertEqual(relpath, 'baz')
 
747
 
 
748
    def test_open_containing_from_transport(self):
 
749
        self.assertRaises(NotBranchError,
 
750
            bzrdir.BzrDir.open_containing_from_transport,
 
751
            _mod_transport.get_transport_from_url(self.get_readonly_url('')))
 
752
        self.assertRaises(NotBranchError,
 
753
            bzrdir.BzrDir.open_containing_from_transport,
 
754
            _mod_transport.get_transport_from_url(
 
755
                self.get_readonly_url('g/p/q')))
 
756
        control = bzrdir.BzrDir.create(self.get_url())
 
757
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
758
            _mod_transport.get_transport_from_url(
 
759
                self.get_readonly_url('')))
 
760
        self.assertEqual('', relpath)
 
761
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
762
            _mod_transport.get_transport_from_url(
 
763
                self.get_readonly_url('g/p/q')))
 
764
        self.assertEqual('g/p/q', relpath)
 
765
 
 
766
    def test_open_containing_tree_or_branch(self):
 
767
        self.make_branch_and_tree('topdir')
 
768
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
769
            'topdir/foo')
 
770
        self.assertEqual(os.path.realpath('topdir'),
 
771
                         os.path.realpath(tree.basedir))
 
772
        self.assertEqual(os.path.realpath('topdir'),
 
773
                         self.local_branch_path(branch))
 
774
        self.assertIs(tree.controldir, branch.controldir)
 
775
        self.assertEqual('foo', relpath)
 
776
        # opening from non-local should not return the tree
 
777
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
778
            self.get_readonly_url('topdir/foo'))
 
779
        self.assertEqual(None, tree)
 
780
        self.assertEqual('foo', relpath)
 
781
        # without a tree:
 
782
        self.make_branch('topdir/foo')
 
783
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
784
            'topdir/foo')
 
785
        self.assertIs(tree, None)
 
786
        self.assertEqual(os.path.realpath('topdir/foo'),
 
787
                         self.local_branch_path(branch))
 
788
        self.assertEqual('', relpath)
 
789
 
 
790
    def test_open_tree_or_branch(self):
 
791
        self.make_branch_and_tree('topdir')
 
792
        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir')
 
793
        self.assertEqual(os.path.realpath('topdir'),
 
794
                         os.path.realpath(tree.basedir))
 
795
        self.assertEqual(os.path.realpath('topdir'),
 
796
                         self.local_branch_path(branch))
 
797
        self.assertIs(tree.controldir, branch.controldir)
 
798
        # opening from non-local should not return the tree
 
799
        tree, branch = bzrdir.BzrDir.open_tree_or_branch(
 
800
            self.get_readonly_url('topdir'))
 
801
        self.assertEqual(None, tree)
 
802
        # without a tree:
 
803
        self.make_branch('topdir/foo')
 
804
        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir/foo')
 
805
        self.assertIs(tree, None)
 
806
        self.assertEqual(os.path.realpath('topdir/foo'),
 
807
                         self.local_branch_path(branch))
 
808
 
 
809
    def test_open_from_transport(self):
 
810
        # transport pointing at bzrdir should give a bzrdir with root transport
 
811
        # set to the given transport
 
812
        control = bzrdir.BzrDir.create(self.get_url())
 
813
        t = self.get_transport()
 
814
        opened_bzrdir = bzrdir.BzrDir.open_from_transport(t)
 
815
        self.assertEqual(t.base, opened_bzrdir.root_transport.base)
 
816
        self.assertIsInstance(opened_bzrdir, bzrdir.BzrDir)
 
817
 
 
818
    def test_open_from_transport_no_bzrdir(self):
 
819
        t = self.get_transport()
 
820
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport, t)
 
821
 
 
822
    def test_open_from_transport_bzrdir_in_parent(self):
 
823
        control = bzrdir.BzrDir.create(self.get_url())
 
824
        t = self.get_transport()
 
825
        t.mkdir('subdir')
 
826
        t = t.clone('subdir')
 
827
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport, t)
 
828
 
 
829
    def test_sprout_recursive(self):
 
830
        tree = self.make_branch_and_tree('tree1',
 
831
                                         format='development-subtree')
 
832
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
833
            format='development-subtree')
 
834
        sub_tree.set_root_id('subtree-root')
 
835
        tree.add_reference(sub_tree)
 
836
        self.build_tree(['tree1/subtree/file'])
 
837
        sub_tree.add('file')
 
838
        tree.commit('Initial commit')
 
839
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
 
840
        tree2.lock_read()
 
841
        self.addCleanup(tree2.unlock)
 
842
        self.assertPathExists('tree2/subtree/file')
 
843
        self.assertEqual('tree-reference', tree2.kind('subtree-root'))
 
844
 
 
845
    def test_cloning_metadir(self):
 
846
        """Ensure that cloning metadir is suitable"""
 
847
        bzrdir = self.make_controldir('bzrdir')
 
848
        bzrdir.cloning_metadir()
 
849
        branch = self.make_branch('branch', format='knit')
 
850
        format = branch.controldir.cloning_metadir()
 
851
        self.assertIsInstance(format.workingtree_format,
 
852
            workingtree_4.WorkingTreeFormat6)
 
853
 
 
854
    def test_sprout_recursive_treeless(self):
 
855
        tree = self.make_branch_and_tree('tree1',
 
856
            format='development-subtree')
 
857
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
858
            format='development-subtree')
 
859
        tree.add_reference(sub_tree)
 
860
        self.build_tree(['tree1/subtree/file'])
 
861
        sub_tree.add('file')
 
862
        tree.commit('Initial commit')
 
863
        # The following line force the orhaning to reveal bug #634470
 
864
        tree.branch.get_config_stack().set(
 
865
            'bzr.transform.orphan_policy', 'move')
 
866
        tree.controldir.destroy_workingtree()
 
867
        # FIXME: subtree/.bzr is left here which allows the test to pass (or
 
868
        # fail :-( ) -- vila 20100909
 
869
        repo = self.make_repository('repo', shared=True,
 
870
            format='development-subtree')
 
871
        repo.set_make_working_trees(False)
 
872
        # FIXME: we just deleted the workingtree and now we want to use it ????
 
873
        # At a minimum, we should use tree.branch below (but this fails too
 
874
        # currently) or stop calling this test 'treeless'. Specifically, I've
 
875
        # turn the line below into an assertRaises when 'subtree/.bzr' is
 
876
        # orphaned and sprout tries to access the branch there (which is left
 
877
        # by bzrdir.BzrDirMeta1.destroy_workingtree when it ignores the
 
878
        # [DeletingParent('Not deleting', u'subtree', None)] conflict). See bug
 
879
        # #634470.  -- vila 20100909
 
880
        self.assertRaises(errors.NotBranchError,
 
881
                          tree.controldir.sprout, 'repo/tree2')
 
882
#        self.assertPathExists('repo/tree2/subtree')
 
883
#        self.assertPathDoesNotExist('repo/tree2/subtree/file')
 
884
 
 
885
    def make_foo_bar_baz(self):
 
886
        foo = bzrdir.BzrDir.create_branch_convenience('foo').controldir
 
887
        bar = self.make_branch('foo/bar').controldir
 
888
        baz = self.make_branch('baz').controldir
 
889
        return foo, bar, baz
 
890
 
 
891
    def test_find_controldirs(self):
 
892
        foo, bar, baz = self.make_foo_bar_baz()
 
893
        t = self.get_transport()
 
894
        self.assertEqualBzrdirs([baz, foo, bar], bzrdir.BzrDir.find_controldirs(t))
 
895
 
 
896
    def make_fake_permission_denied_transport(self, transport, paths):
 
897
        """Create a transport that raises PermissionDenied for some paths."""
 
898
        def filter(path):
 
899
            if path in paths:
 
900
                raise errors.PermissionDenied(path)
 
901
            return path
 
902
        path_filter_server = pathfilter.PathFilteringServer(transport, filter)
 
903
        path_filter_server.start_server()
 
904
        self.addCleanup(path_filter_server.stop_server)
 
905
        path_filter_transport = pathfilter.PathFilteringTransport(
 
906
            path_filter_server, '.')
 
907
        return (path_filter_server, path_filter_transport)
 
908
 
 
909
    def assertBranchUrlsEndWith(self, expect_url_suffix, actual_bzrdirs):
 
910
        """Check that each branch url ends with the given suffix."""
 
911
        for actual_bzrdir in actual_bzrdirs:
 
912
            self.assertEndsWith(actual_bzrdir.user_url, expect_url_suffix)
 
913
 
 
914
    def test_find_controldirs_permission_denied(self):
 
915
        foo, bar, baz = self.make_foo_bar_baz()
 
916
        t = self.get_transport()
 
917
        path_filter_server, path_filter_transport = \
 
918
            self.make_fake_permission_denied_transport(t, ['foo'])
 
919
        # local transport
 
920
        self.assertBranchUrlsEndWith('/baz/',
 
921
            bzrdir.BzrDir.find_controldirs(path_filter_transport))
 
922
        # smart server
 
923
        smart_transport = self.make_smart_server('.',
 
924
            backing_server=path_filter_server)
 
925
        self.assertBranchUrlsEndWith('/baz/',
 
926
            bzrdir.BzrDir.find_controldirs(smart_transport))
 
927
 
 
928
    def test_find_controldirs_list_current(self):
 
929
        def list_current(transport):
 
930
            return [s for s in transport.list_dir('') if s != 'baz']
 
931
 
 
932
        foo, bar, baz = self.make_foo_bar_baz()
 
933
        t = self.get_transport()
 
934
        self.assertEqualBzrdirs(
 
935
            [foo, bar],
 
936
            bzrdir.BzrDir.find_controldirs(t, list_current=list_current))
 
937
 
 
938
    def test_find_controldirs_evaluate(self):
 
939
        def evaluate(bzrdir):
 
940
            try:
 
941
                repo = bzrdir.open_repository()
 
942
            except errors.NoRepositoryPresent:
 
943
                return True, bzrdir.root_transport.base
 
944
            else:
 
945
                return False, bzrdir.root_transport.base
 
946
 
 
947
        foo, bar, baz = self.make_foo_bar_baz()
 
948
        t = self.get_transport()
 
949
        self.assertEqual([baz.root_transport.base, foo.root_transport.base],
 
950
                         list(bzrdir.BzrDir.find_controldirs(t, evaluate=evaluate)))
 
951
 
 
952
    def assertEqualBzrdirs(self, first, second):
 
953
        first = list(first)
 
954
        second = list(second)
 
955
        self.assertEqual(len(first), len(second))
 
956
        for x, y in zip(first, second):
 
957
            self.assertEqual(x.root_transport.base, y.root_transport.base)
 
958
 
 
959
    def test_find_branches(self):
 
960
        root = self.make_repository('', shared=True)
 
961
        foo, bar, baz = self.make_foo_bar_baz()
 
962
        qux = self.make_controldir('foo/qux')
 
963
        t = self.get_transport()
 
964
        branches = bzrdir.BzrDir.find_branches(t)
 
965
        self.assertEqual(baz.root_transport.base, branches[0].base)
 
966
        self.assertEqual(foo.root_transport.base, branches[1].base)
 
967
        self.assertEqual(bar.root_transport.base, branches[2].base)
 
968
 
 
969
        # ensure this works without a top-level repo
 
970
        branches = bzrdir.BzrDir.find_branches(t.clone('foo'))
 
971
        self.assertEqual(foo.root_transport.base, branches[0].base)
 
972
        self.assertEqual(bar.root_transport.base, branches[1].base)
 
973
 
 
974
 
 
975
class TestMissingRepoBranchesSkipped(TestCaseWithMemoryTransport):
 
976
 
 
977
    def test_find_controldirs_missing_repo(self):
 
978
        t = self.get_transport()
 
979
        arepo = self.make_repository('arepo', shared=True)
 
980
        abranch_url = arepo.user_url + '/abranch'
 
981
        abranch = bzrdir.BzrDir.create(abranch_url).create_branch()
 
982
        t.delete_tree('arepo/.bzr')
 
983
        self.assertRaises(errors.NoRepositoryPresent,
 
984
            branch.Branch.open, abranch_url)
 
985
        self.make_branch('baz')
 
986
        for actual_bzrdir in bzrdir.BzrDir.find_branches(t):
 
987
            self.assertEndsWith(actual_bzrdir.user_url, '/baz/')
 
988
 
 
989
 
 
990
class TestMeta1DirFormat(TestCaseWithTransport):
 
991
    """Tests specific to the meta1 dir format."""
 
992
 
 
993
    def test_right_base_dirs(self):
 
994
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
995
        t = dir.transport
 
996
        branch_base = t.clone('branch').base
 
997
        self.assertEqual(branch_base, dir.get_branch_transport(None).base)
 
998
        self.assertEqual(branch_base,
 
999
                         dir.get_branch_transport(BzrBranchFormat5()).base)
 
1000
        repository_base = t.clone('repository').base
 
1001
        self.assertEqual(repository_base, dir.get_repository_transport(None).base)
 
1002
        repository_format = repository.format_registry.get_default()
 
1003
        self.assertEqual(repository_base,
 
1004
                         dir.get_repository_transport(repository_format).base)
 
1005
        checkout_base = t.clone('checkout').base
 
1006
        self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
 
1007
        self.assertEqual(checkout_base,
 
1008
                         dir.get_workingtree_transport(workingtree_3.WorkingTreeFormat3()).base)
 
1009
 
 
1010
    def test_meta1dir_uses_lockdir(self):
 
1011
        """Meta1 format uses a LockDir to guard the whole directory, not a file."""
 
1012
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
1013
        t = dir.transport
 
1014
        self.assertIsDirectory('branch-lock', t)
 
1015
 
 
1016
    def test_comparison(self):
 
1017
        """Equality and inequality behave properly.
 
1018
 
 
1019
        Metadirs should compare equal iff they have the same repo, branch and
 
1020
        tree formats.
 
1021
        """
 
1022
        mydir = controldir.format_registry.make_controldir('knit')
 
1023
        self.assertEqual(mydir, mydir)
 
1024
        self.assertFalse(mydir != mydir)
 
1025
        otherdir = controldir.format_registry.make_controldir('knit')
 
1026
        self.assertEqual(otherdir, mydir)
 
1027
        self.assertFalse(otherdir != mydir)
 
1028
        otherdir2 = controldir.format_registry.make_controldir('development-subtree')
 
1029
        self.assertNotEqual(otherdir2, mydir)
 
1030
        self.assertFalse(otherdir2 == mydir)
 
1031
 
 
1032
    def test_with_features(self):
 
1033
        tree = self.make_branch_and_tree('tree', format='2a')
 
1034
        tree.controldir.update_feature_flags({"bar": "required"})
 
1035
        self.assertRaises(bzrdir.MissingFeature, bzrdir.BzrDir.open, 'tree')
 
1036
        bzrdir.BzrDirMetaFormat1.register_feature('bar')
 
1037
        self.addCleanup(bzrdir.BzrDirMetaFormat1.unregister_feature, 'bar')
 
1038
        dir = bzrdir.BzrDir.open('tree')
 
1039
        self.assertEqual("required", dir._format.features.get("bar"))
 
1040
        tree.controldir.update_feature_flags({"bar": None, "nonexistant": None})
 
1041
        dir = bzrdir.BzrDir.open('tree')
 
1042
        self.assertEqual({}, dir._format.features)
 
1043
 
 
1044
    def test_needs_conversion_different_working_tree(self):
 
1045
        # meta1dirs need an conversion if any element is not the default.
 
1046
        new_format = controldir.format_registry.make_controldir('dirstate')
 
1047
        tree = self.make_branch_and_tree('tree', format='knit')
 
1048
        self.assertTrue(tree.controldir.needs_format_conversion(
 
1049
            new_format))
 
1050
 
 
1051
    def test_initialize_on_format_uses_smart_transport(self):
 
1052
        self.setup_smart_server_with_call_log()
 
1053
        new_format = controldir.format_registry.make_controldir('dirstate')
 
1054
        transport = self.get_transport('target')
 
1055
        transport.ensure_base()
 
1056
        self.reset_smart_call_log()
 
1057
        instance = new_format.initialize_on_transport(transport)
 
1058
        self.assertIsInstance(instance, remote.RemoteBzrDir)
 
1059
        rpc_count = len(self.hpss_calls)
 
1060
        # This figure represent the amount of work to perform this use case. It
 
1061
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
1062
        # being too low. If rpc_count increases, more network roundtrips have
 
1063
        # become necessary for this use case. Please do not adjust this number
 
1064
        # upwards without agreement from bzr's network support maintainers.
 
1065
        self.assertEqual(2, rpc_count)
 
1066
 
 
1067
 
 
1068
class NonLocalTests(TestCaseWithTransport):
 
1069
    """Tests for bzrdir static behaviour on non local paths."""
 
1070
 
 
1071
    def setUp(self):
 
1072
        super(NonLocalTests, self).setUp()
 
1073
        self.vfs_transport_factory = memory.MemoryServer
 
1074
 
 
1075
    def test_create_branch_convenience(self):
 
1076
        # outside a repo the default convenience output is a repo+branch_tree
 
1077
        format = controldir.format_registry.make_controldir('knit')
 
1078
        branch = bzrdir.BzrDir.create_branch_convenience(
 
1079
            self.get_url('foo'), format=format)
 
1080
        self.assertRaises(errors.NoWorkingTree,
 
1081
                          branch.controldir.open_workingtree)
 
1082
        branch.controldir.open_repository()
 
1083
 
 
1084
    def test_create_branch_convenience_force_tree_not_local_fails(self):
 
1085
        # outside a repo the default convenience output is a repo+branch_tree
 
1086
        format = controldir.format_registry.make_controldir('knit')
 
1087
        self.assertRaises(errors.NotLocalUrl,
 
1088
            bzrdir.BzrDir.create_branch_convenience,
 
1089
            self.get_url('foo'),
 
1090
            force_new_tree=True,
 
1091
            format=format)
 
1092
        t = self.get_transport()
 
1093
        self.assertFalse(t.has('foo'))
 
1094
 
 
1095
    def test_clone(self):
 
1096
        # clone into a nonlocal path works
 
1097
        format = controldir.format_registry.make_controldir('knit')
 
1098
        branch = bzrdir.BzrDir.create_branch_convenience('local',
 
1099
                                                         format=format)
 
1100
        branch.controldir.open_workingtree()
 
1101
        result = branch.controldir.clone(self.get_url('remote'))
 
1102
        self.assertRaises(errors.NoWorkingTree,
 
1103
                          result.open_workingtree)
 
1104
        result.open_branch()
 
1105
        result.open_repository()
 
1106
 
 
1107
    def test_checkout_metadir(self):
 
1108
        # checkout_metadir has reasonable working tree format even when no
 
1109
        # working tree is present
 
1110
        self.make_branch('branch-knit2', format='dirstate-with-subtree')
 
1111
        my_bzrdir = bzrdir.BzrDir.open(self.get_url('branch-knit2'))
 
1112
        checkout_format = my_bzrdir.checkout_metadir()
 
1113
        self.assertIsInstance(checkout_format.workingtree_format,
 
1114
                              workingtree_4.WorkingTreeFormat4)
 
1115
 
 
1116
 
 
1117
class TestHTTPRedirections(object):
 
1118
    """Test redirection between two http servers.
 
1119
 
 
1120
    This MUST be used by daughter classes that also inherit from
 
1121
    TestCaseWithTwoWebservers.
 
1122
 
 
1123
    We can't inherit directly from TestCaseWithTwoWebservers or the
 
1124
    test framework will try to create an instance which cannot
 
1125
    run, its implementation being incomplete.
 
1126
    """
 
1127
 
 
1128
    def create_transport_readonly_server(self):
 
1129
        # We don't set the http protocol version, relying on the default
 
1130
        return http_utils.HTTPServerRedirecting()
 
1131
 
 
1132
    def create_transport_secondary_server(self):
 
1133
        # We don't set the http protocol version, relying on the default
 
1134
        return http_utils.HTTPServerRedirecting()
 
1135
 
 
1136
    def setUp(self):
 
1137
        super(TestHTTPRedirections, self).setUp()
 
1138
        # The redirections will point to the new server
 
1139
        self.new_server = self.get_readonly_server()
 
1140
        # The requests to the old server will be redirected
 
1141
        self.old_server = self.get_secondary_server()
 
1142
        # Configure the redirections
 
1143
        self.old_server.redirect_to(self.new_server.host, self.new_server.port)
 
1144
 
 
1145
    def test_loop(self):
 
1146
        # Both servers redirect to each other creating a loop
 
1147
        self.new_server.redirect_to(self.old_server.host, self.old_server.port)
 
1148
        # Starting from either server should loop
 
1149
        old_url = self._qualified_url(self.old_server.host,
 
1150
                                      self.old_server.port)
 
1151
        oldt = self._transport(old_url)
 
1152
        self.assertRaises(errors.NotBranchError,
 
1153
                          bzrdir.BzrDir.open_from_transport, oldt)
 
1154
        new_url = self._qualified_url(self.new_server.host,
 
1155
                                      self.new_server.port)
 
1156
        newt = self._transport(new_url)
 
1157
        self.assertRaises(errors.NotBranchError,
 
1158
                          bzrdir.BzrDir.open_from_transport, newt)
 
1159
 
 
1160
    def test_qualifier_preserved(self):
 
1161
        wt = self.make_branch_and_tree('branch')
 
1162
        old_url = self._qualified_url(self.old_server.host,
 
1163
                                      self.old_server.port)
 
1164
        start = self._transport(old_url).clone('branch')
 
1165
        bdir = bzrdir.BzrDir.open_from_transport(start)
 
1166
        # Redirection should preserve the qualifier, hence the transport class
 
1167
        # itself.
 
1168
        self.assertIsInstance(bdir.root_transport, type(start))
 
1169
 
 
1170
 
 
1171
class TestHTTPRedirections_urllib(TestHTTPRedirections,
 
1172
                                  http_utils.TestCaseWithTwoWebservers):
 
1173
    """Tests redirections for urllib implementation"""
 
1174
 
 
1175
    _transport = HttpTransport_urllib
 
1176
 
 
1177
    def _qualified_url(self, host, port):
 
1178
        result = 'http+urllib://%s:%s' % (host, port)
 
1179
        self.permit_url(result)
 
1180
        return result
 
1181
 
 
1182
 
 
1183
 
 
1184
class TestHTTPRedirections_nosmart(TestHTTPRedirections,
 
1185
                                  http_utils.TestCaseWithTwoWebservers):
 
1186
    """Tests redirections for the nosmart decorator"""
 
1187
 
 
1188
    _transport = NoSmartTransportDecorator
 
1189
 
 
1190
    def _qualified_url(self, host, port):
 
1191
        result = 'nosmart+http://%s:%s' % (host, port)
 
1192
        self.permit_url(result)
 
1193
        return result
 
1194
 
 
1195
 
 
1196
class TestHTTPRedirections_readonly(TestHTTPRedirections,
 
1197
                                    http_utils.TestCaseWithTwoWebservers):
 
1198
    """Tests redirections for readonly decoratror"""
 
1199
 
 
1200
    _transport = ReadonlyTransportDecorator
 
1201
 
 
1202
    def _qualified_url(self, host, port):
 
1203
        result = 'readonly+http://%s:%s' % (host, port)
 
1204
        self.permit_url(result)
 
1205
        return result
 
1206
 
 
1207
 
 
1208
class TestDotBzrHidden(TestCaseWithTransport):
 
1209
 
 
1210
    ls = ['ls']
 
1211
    if sys.platform == 'win32':
 
1212
        ls = [os.environ['COMSPEC'], '/C', 'dir', '/B']
 
1213
 
 
1214
    def get_ls(self):
 
1215
        f = subprocess.Popen(self.ls, stdout=subprocess.PIPE,
 
1216
            stderr=subprocess.PIPE)
 
1217
        out, err = f.communicate()
 
1218
        self.assertEqual(0, f.returncode, 'Calling %s failed: %s'
 
1219
                         % (self.ls, err))
 
1220
        return out.splitlines()
 
1221
 
 
1222
    def test_dot_bzr_hidden(self):
 
1223
        if sys.platform == 'win32' and not win32utils.has_win32file:
 
1224
            raise TestSkipped('unable to make file hidden without pywin32 library')
 
1225
        b = bzrdir.BzrDir.create('.')
 
1226
        self.build_tree(['a'])
 
1227
        self.assertEqual(['a'], self.get_ls())
 
1228
 
 
1229
    def test_dot_bzr_hidden_with_url(self):
 
1230
        if sys.platform == 'win32' and not win32utils.has_win32file:
 
1231
            raise TestSkipped('unable to make file hidden without pywin32 library')
 
1232
        b = bzrdir.BzrDir.create(urlutils.local_path_to_url('.'))
 
1233
        self.build_tree(['a'])
 
1234
        self.assertEqual(['a'], self.get_ls())
 
1235
 
 
1236
 
 
1237
class _TestBzrDirFormat(bzrdir.BzrDirMetaFormat1):
 
1238
    """Test BzrDirFormat implementation for TestBzrDirSprout."""
 
1239
 
 
1240
    def _open(self, transport):
 
1241
        return _TestBzrDir(transport, self)
 
1242
 
 
1243
 
 
1244
class _TestBzrDir(bzrdir.BzrDirMeta1):
 
1245
    """Test BzrDir implementation for TestBzrDirSprout.
 
1246
 
 
1247
    When created a _TestBzrDir already has repository and a branch.  The branch
 
1248
    is a test double as well.
 
1249
    """
 
1250
 
 
1251
    def __init__(self, *args, **kwargs):
 
1252
        super(_TestBzrDir, self).__init__(*args, **kwargs)
 
1253
        self.test_branch = _TestBranch(self.transport)
 
1254
        self.test_branch.repository = self.create_repository()
 
1255
 
 
1256
    def open_branch(self, unsupported=False, possible_transports=None):
 
1257
        return self.test_branch
 
1258
 
 
1259
    def cloning_metadir(self, require_stacking=False):
 
1260
        return _TestBzrDirFormat()
 
1261
 
 
1262
 
 
1263
class _TestBranchFormat(breezy.branch.BranchFormat):
 
1264
    """Test Branch format for TestBzrDirSprout."""
 
1265
 
 
1266
 
 
1267
class _TestBranch(breezy.branch.Branch):
 
1268
    """Test Branch implementation for TestBzrDirSprout."""
 
1269
 
 
1270
    def __init__(self, transport, *args, **kwargs):
 
1271
        self._format = _TestBranchFormat()
 
1272
        self._transport = transport
 
1273
        self.base = transport.base
 
1274
        super(_TestBranch, self).__init__(*args, **kwargs)
 
1275
        self.calls = []
 
1276
        self._parent = None
 
1277
 
 
1278
    def sprout(self, *args, **kwargs):
 
1279
        self.calls.append('sprout')
 
1280
        return _TestBranch(self._transport)
 
1281
 
 
1282
    def copy_content_into(self, destination, revision_id=None):
 
1283
        self.calls.append('copy_content_into')
 
1284
 
 
1285
    def last_revision(self):
 
1286
        return _mod_revision.NULL_REVISION
 
1287
 
 
1288
    def get_parent(self):
 
1289
        return self._parent
 
1290
 
 
1291
    def _get_config(self):
 
1292
        return config.TransportConfig(self._transport, 'branch.conf')
 
1293
 
 
1294
    def _get_config_store(self):
 
1295
        return config.BranchStore(self)
 
1296
 
 
1297
    def set_parent(self, parent):
 
1298
        self._parent = parent
 
1299
 
 
1300
    def lock_read(self):
 
1301
        return lock.LogicalLockResult(self.unlock)
 
1302
 
 
1303
    def unlock(self):
 
1304
        return
 
1305
 
 
1306
 
 
1307
class TestBzrDirSprout(TestCaseWithMemoryTransport):
 
1308
 
 
1309
    def test_sprout_uses_branch_sprout(self):
 
1310
        """BzrDir.sprout calls Branch.sprout.
 
1311
 
 
1312
        Usually, BzrDir.sprout should delegate to the branch's sprout method
 
1313
        for part of the work.  This allows the source branch to control the
 
1314
        choice of format for the new branch.
 
1315
 
 
1316
        There are exceptions, but this tests avoids them:
 
1317
          - if there's no branch in the source bzrdir,
 
1318
          - or if the stacking has been requested and the format needs to be
 
1319
            overridden to satisfy that.
 
1320
        """
 
1321
        # Make an instrumented bzrdir.
 
1322
        t = self.get_transport('source')
 
1323
        t.ensure_base()
 
1324
        source_bzrdir = _TestBzrDirFormat().initialize_on_transport(t)
 
1325
        # The instrumented bzrdir has a test_branch attribute that logs calls
 
1326
        # made to the branch contained in that bzrdir.  Initially the test
 
1327
        # branch exists but no calls have been made to it.
 
1328
        self.assertEqual([], source_bzrdir.test_branch.calls)
 
1329
 
 
1330
        # Sprout the bzrdir
 
1331
        target_url = self.get_url('target')
 
1332
        result = source_bzrdir.sprout(target_url, recurse='no')
 
1333
 
 
1334
        # The bzrdir called the branch's sprout method.
 
1335
        self.assertSubset(['sprout'], source_bzrdir.test_branch.calls)
 
1336
 
 
1337
    def test_sprout_parent(self):
 
1338
        grandparent_tree = self.make_branch('grandparent')
 
1339
        parent = grandparent_tree.controldir.sprout('parent').open_branch()
 
1340
        branch_tree = parent.controldir.sprout('branch').open_branch()
 
1341
        self.assertContainsRe(branch_tree.get_parent(), '/parent/$')
 
1342
 
 
1343
 
 
1344
class TestBzrDirHooks(TestCaseWithMemoryTransport):
 
1345
 
 
1346
    def test_pre_open_called(self):
 
1347
        calls = []
 
1348
        bzrdir.BzrDir.hooks.install_named_hook('pre_open', calls.append, None)
 
1349
        transport = self.get_transport('foo')
 
1350
        url = transport.base
 
1351
        self.assertRaises(errors.NotBranchError, bzrdir.BzrDir.open, url)
 
1352
        self.assertEqual([transport.base], [t.base for t in calls])
 
1353
 
 
1354
    def test_pre_open_actual_exceptions_raised(self):
 
1355
        count = [0]
 
1356
        def fail_once(transport):
 
1357
            count[0] += 1
 
1358
            if count[0] == 1:
 
1359
                raise errors.BzrError("fail")
 
1360
        bzrdir.BzrDir.hooks.install_named_hook('pre_open', fail_once, None)
 
1361
        transport = self.get_transport('foo')
 
1362
        url = transport.base
 
1363
        err = self.assertRaises(errors.BzrError, bzrdir.BzrDir.open, url)
 
1364
        self.assertEqual('fail', err._preformatted_string)
 
1365
 
 
1366
    def test_post_repo_init(self):
 
1367
        from ..controldir import RepoInitHookParams
 
1368
        calls = []
 
1369
        bzrdir.BzrDir.hooks.install_named_hook('post_repo_init',
 
1370
            calls.append, None)
 
1371
        self.make_repository('foo')
 
1372
        self.assertLength(1, calls)
 
1373
        params = calls[0]
 
1374
        self.assertIsInstance(params, RepoInitHookParams)
 
1375
        self.assertTrue(hasattr(params, 'controldir'))
 
1376
        self.assertTrue(hasattr(params, 'repository'))
 
1377
 
 
1378
    def test_post_repo_init_hook_repr(self):
 
1379
        param_reprs = []
 
1380
        bzrdir.BzrDir.hooks.install_named_hook('post_repo_init',
 
1381
            lambda params: param_reprs.append(repr(params)), None)
 
1382
        self.make_repository('foo')
 
1383
        self.assertLength(1, param_reprs)
 
1384
        param_repr = param_reprs[0]
 
1385
        self.assertStartsWith(param_repr, '<RepoInitHookParams for ')
 
1386
 
 
1387
 
 
1388
class TestGenerateBackupName(TestCaseWithMemoryTransport):
 
1389
    # FIXME: This may need to be unified with test_osutils.TestBackupNames or
 
1390
    # moved to per_bzrdir or per_transport for better coverage ?
 
1391
    # -- vila 20100909
 
1392
 
 
1393
    def setUp(self):
 
1394
        super(TestGenerateBackupName, self).setUp()
 
1395
        self._transport = self.get_transport()
 
1396
        bzrdir.BzrDir.create(self.get_url(),
 
1397
            possible_transports=[self._transport])
 
1398
        self._bzrdir = bzrdir.BzrDir.open_from_transport(self._transport)
 
1399
 
 
1400
    def test_new(self):
 
1401
        self.assertEqual("a.~1~", self._bzrdir._available_backup_name("a"))
 
1402
 
 
1403
    def test_exiting(self):
 
1404
        self._transport.put_bytes("a.~1~", "some content")
 
1405
        self.assertEqual("a.~2~", self._bzrdir._available_backup_name("a"))
 
1406
 
 
1407
 
 
1408
class TestMeta1DirColoFormat(TestCaseWithTransport):
 
1409
    """Tests specific to the meta1 dir with colocated branches format."""
 
1410
 
 
1411
    def test_supports_colo(self):
 
1412
        format = bzrdir.BzrDirMetaFormat1Colo()
 
1413
        self.assertTrue(format.colocated_branches)
 
1414
 
 
1415
    def test_upgrade_from_2a(self):
 
1416
        tree = self.make_branch_and_tree('.', format='2a')
 
1417
        format = bzrdir.BzrDirMetaFormat1Colo()
 
1418
        self.assertTrue(tree.controldir.needs_format_conversion(format))
 
1419
        converter = tree.controldir._format.get_converter(format)
 
1420
        result = converter.convert(tree.controldir, None)
 
1421
        self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1Colo)
 
1422
        self.assertFalse(result.needs_format_conversion(format))
 
1423
 
 
1424
    def test_downgrade_to_2a(self):
 
1425
        tree = self.make_branch_and_tree('.', format='development-colo')
 
1426
        format = bzrdir.BzrDirMetaFormat1()
 
1427
        self.assertTrue(tree.controldir.needs_format_conversion(format))
 
1428
        converter = tree.controldir._format.get_converter(format)
 
1429
        result = converter.convert(tree.controldir, None)
 
1430
        self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1)
 
1431
        self.assertFalse(result.needs_format_conversion(format))
 
1432
 
 
1433
    def test_downgrade_to_2a_too_many_branches(self):
 
1434
        tree = self.make_branch_and_tree('.', format='development-colo')
 
1435
        tree.controldir.create_branch(name="another-colocated-branch")
 
1436
        converter = tree.controldir._format.get_converter(
 
1437
            bzrdir.BzrDirMetaFormat1())
 
1438
        result = converter.convert(tree.controldir, bzrdir.BzrDirMetaFormat1())
 
1439
        self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1)
 
1440
 
 
1441
    def test_nested(self):
 
1442
        tree = self.make_branch_and_tree('.', format='development-colo')
 
1443
        tree.controldir.create_branch(name='foo')
 
1444
        tree.controldir.create_branch(name='fool/bla')
 
1445
        self.assertRaises(
 
1446
            errors.ParentBranchExists, tree.controldir.create_branch,
 
1447
            name='foo/bar')
 
1448
 
 
1449
    def test_parent(self):
 
1450
        tree = self.make_branch_and_tree('.', format='development-colo')
 
1451
        tree.controldir.create_branch(name='fool/bla')
 
1452
        tree.controldir.create_branch(name='foo/bar')
 
1453
        self.assertRaises(
 
1454
            errors.AlreadyBranchError, tree.controldir.create_branch,
 
1455
            name='foo')
 
1456
 
 
1457
 
 
1458
class SampleBzrFormat(bzrdir.BzrFormat):
 
1459
 
 
1460
    @classmethod
 
1461
    def get_format_string(cls):
 
1462
        return "First line\n"
 
1463
 
 
1464
 
 
1465
class TestBzrFormat(TestCase):
 
1466
    """Tests for BzrFormat."""
 
1467
 
 
1468
    def test_as_string(self):
 
1469
        format = SampleBzrFormat()
 
1470
        format.features = {"foo": "required"}
 
1471
        self.assertEqual(format.as_string(),
 
1472
            "First line\n"
 
1473
            "required foo\n")
 
1474
        format.features["another"] = "optional"
 
1475
        self.assertEqual(format.as_string(),
 
1476
            "First line\n"
 
1477
            "required foo\n"
 
1478
            "optional another\n")
 
1479
 
 
1480
    def test_network_name(self):
 
1481
        # The network string should include the feature info
 
1482
        format = SampleBzrFormat()
 
1483
        format.features = {"foo": "required"}
 
1484
        self.assertEqual(
 
1485
            "First line\nrequired foo\n",
 
1486
            format.network_name())
 
1487
 
 
1488
    def test_from_string_no_features(self):
 
1489
        # No features
 
1490
        format = SampleBzrFormat.from_string(
 
1491
            "First line\n")
 
1492
        self.assertEqual({}, format.features)
 
1493
 
 
1494
    def test_from_string_with_feature(self):
 
1495
        # Proper feature
 
1496
        format = SampleBzrFormat.from_string(
 
1497
            "First line\nrequired foo\n")
 
1498
        self.assertEqual("required", format.features.get("foo"))
 
1499
 
 
1500
    def test_from_string_format_string_mismatch(self):
 
1501
        # The first line has to match the format string
 
1502
        self.assertRaises(AssertionError, SampleBzrFormat.from_string,
 
1503
            "Second line\nrequired foo\n")
 
1504
 
 
1505
    def test_from_string_missing_space(self):
 
1506
        # At least one space is required in the feature lines
 
1507
        self.assertRaises(errors.ParseFormatError, SampleBzrFormat.from_string,
 
1508
            "First line\nfoo\n")
 
1509
 
 
1510
    def test_from_string_with_spaces(self):
 
1511
        # Feature with spaces (in case we add stuff like this in the future)
 
1512
        format = SampleBzrFormat.from_string(
 
1513
            "First line\nrequired foo with spaces\n")
 
1514
        self.assertEqual("required", format.features.get("foo with spaces"))
 
1515
 
 
1516
    def test_eq(self):
 
1517
        format1 = SampleBzrFormat()
 
1518
        format1.features = {"nested-trees": "optional"}
 
1519
        format2 = SampleBzrFormat()
 
1520
        format2.features = {"nested-trees": "optional"}
 
1521
        self.assertEqual(format1, format1)
 
1522
        self.assertEqual(format1, format2)
 
1523
        format3 = SampleBzrFormat()
 
1524
        self.assertNotEqual(format1, format3)
 
1525
 
 
1526
    def test_check_support_status_optional(self):
 
1527
        # Optional, so silently ignore
 
1528
        format = SampleBzrFormat()
 
1529
        format.features = {"nested-trees": "optional"}
 
1530
        format.check_support_status(True)
 
1531
        self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
 
1532
        SampleBzrFormat.register_feature("nested-trees")
 
1533
        format.check_support_status(True)
 
1534
 
 
1535
    def test_check_support_status_required(self):
 
1536
        # Optional, so trigger an exception
 
1537
        format = SampleBzrFormat()
 
1538
        format.features = {"nested-trees": "required"}
 
1539
        self.assertRaises(bzrdir.MissingFeature, format.check_support_status,
 
1540
            True)
 
1541
        self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
 
1542
        SampleBzrFormat.register_feature("nested-trees")
 
1543
        format.check_support_status(True)
 
1544
 
 
1545
    def test_check_support_status_unknown(self):
 
1546
        # treat unknown necessity as required
 
1547
        format = SampleBzrFormat()
 
1548
        format.features = {"nested-trees": "unknown"}
 
1549
        self.assertRaises(bzrdir.MissingFeature, format.check_support_status,
 
1550
            True)
 
1551
        self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
 
1552
        SampleBzrFormat.register_feature("nested-trees")
 
1553
        format.check_support_status(True)
 
1554
 
 
1555
    def test_feature_already_registered(self):
 
1556
        # a feature can only be registered once
 
1557
        self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
 
1558
        SampleBzrFormat.register_feature("nested-trees")
 
1559
        self.assertRaises(bzrdir.FeatureAlreadyRegistered,
 
1560
            SampleBzrFormat.register_feature, "nested-trees")
 
1561
 
 
1562
    def test_feature_with_space(self):
 
1563
        # spaces are not allowed in feature names
 
1564
        self.assertRaises(ValueError, SampleBzrFormat.register_feature,
 
1565
            "nested trees")