/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_errors.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-05-06 03:06:18 UTC
  • mfrom: (7500.1.2 trunk-merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200506030618-131sjbc876q7on66
Merge the 3.1 branch.

Merged from https://code.launchpad.net/~jelmer/brz/trunk-merge-3.1/+merge/383481

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 by Canonical Ltd
2
 
#   Authors: Robert Collins <robert.collins@canonical.com>
 
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
13
12
#
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
16
 
18
17
"""Tests for the formatting and construction of errors."""
19
18
 
20
 
import bzrlib.bzrdir as bzrdir
21
 
import bzrlib.errors as errors
22
 
from bzrlib.tests import TestCaseWithTransport
23
 
 
24
 
 
25
 
class TestErrors(TestCaseWithTransport):
 
19
import inspect
 
20
import re
 
21
import socket
 
22
import sys
 
23
 
 
24
from .. import (
 
25
    controldir,
 
26
    errors,
 
27
    osutils,
 
28
    tests,
 
29
    urlutils,
 
30
    )
 
31
 
 
32
 
 
33
class TestErrors(tests.TestCase):
 
34
 
 
35
    def test_no_arg_named_message(self):
 
36
        """Ensure the __init__ and _fmt in errors do not have "message" arg.
 
37
 
 
38
        This test fails if __init__ or _fmt in errors has an argument
 
39
        named "message" as this can cause errors in some Python versions.
 
40
        Python 2.5 uses a slot for StandardError.message.
 
41
        See bug #603461
 
42
        """
 
43
        fmt_pattern = re.compile("%\\(message\\)[sir]")
 
44
        for c in errors.BzrError.__subclasses__():
 
45
            init = getattr(c, '__init__', None)
 
46
            fmt = getattr(c, '_fmt', None)
 
47
            if init:
 
48
                args = inspect.getfullargspec(init)[0]
 
49
                self.assertFalse('message' in args,
 
50
                                 ('Argument name "message" not allowed for '
 
51
                                  '"errors.%s.__init__"' % c.__name__))
 
52
            if fmt and fmt_pattern.search(fmt):
 
53
                self.assertFalse(True, ('"message" not allowed in '
 
54
                                        '"errors.%s._fmt"' % c.__name__))
 
55
 
 
56
    def test_bad_filename_encoding(self):
 
57
        error = errors.BadFilenameEncoding(b'bad/filen\xe5me', 'UTF-8')
 
58
        self.assertContainsRe(
 
59
            str(error),
 
60
            "^Filename b?'bad/filen\\\\xe5me' is not valid in your current"
 
61
            " filesystem encoding UTF-8$")
 
62
 
 
63
    def test_duplicate_file_id(self):
 
64
        error = errors.DuplicateFileId('a_file_id', 'foo')
 
65
        self.assertEqualDiff('File id {a_file_id} already exists in inventory'
 
66
                             ' as foo', str(error))
 
67
 
 
68
    def test_duplicate_help_prefix(self):
 
69
        error = errors.DuplicateHelpPrefix('foo')
 
70
        self.assertEqualDiff('The prefix foo is in the help search path twice.',
 
71
                             str(error))
 
72
 
 
73
    def test_ghost_revisions_have_no_revno(self):
 
74
        error = errors.GhostRevisionsHaveNoRevno('target', 'ghost_rev')
 
75
        self.assertEqualDiff("Could not determine revno for {target} because"
 
76
                             " its ancestry shows a ghost at {ghost_rev}",
 
77
                             str(error))
 
78
 
 
79
    def test_incompatibleVersion(self):
 
80
        error = errors.IncompatibleVersion("module", [(4, 5, 6), (7, 8, 9)],
 
81
                                           (1, 2, 3))
 
82
        self.assertEqualDiff(
 
83
            'API module is not compatible; one of versions '
 
84
            '[(4, 5, 6), (7, 8, 9)] is required, but current version is '
 
85
            '(1, 2, 3).',
 
86
            str(error))
 
87
 
 
88
    def test_inconsistent_delta(self):
 
89
        error = errors.InconsistentDelta('path', 'file-id', 'reason for foo')
 
90
        self.assertEqualDiff(
 
91
            "An inconsistent delta was supplied involving 'path', 'file-id'\n"
 
92
            "reason: reason for foo",
 
93
            str(error))
 
94
 
 
95
    def test_inconsistent_delta_delta(self):
 
96
        error = errors.InconsistentDeltaDelta([], 'reason')
 
97
        self.assertEqualDiff(
 
98
            "An inconsistent delta was supplied: []\nreason: reason",
 
99
            str(error))
 
100
 
 
101
    def test_in_process_transport(self):
 
102
        error = errors.InProcessTransport('fpp')
 
103
        self.assertEqualDiff(
 
104
            "The transport 'fpp' is only accessible within this process.",
 
105
            str(error))
 
106
 
 
107
    def test_invalid_http_range(self):
 
108
        error = errors.InvalidHttpRange('path',
 
109
                                        'Content-Range: potatoes 0-00/o0oo0',
 
110
                                        'bad range')
 
111
        self.assertEqual("Invalid http range"
 
112
                         " 'Content-Range: potatoes 0-00/o0oo0'"
 
113
                         " for path: bad range",
 
114
                         str(error))
 
115
 
 
116
    def test_invalid_range(self):
 
117
        error = errors.InvalidRange('path', 12, 'bad range')
 
118
        self.assertEqual("Invalid range access in path at 12: bad range",
 
119
                         str(error))
 
120
 
 
121
    def test_inventory_modified(self):
 
122
        error = errors.InventoryModified("a tree to be repred")
 
123
        self.assertEqualDiff("The current inventory for the tree 'a tree to "
 
124
                             "be repred' has been modified, so a clean inventory cannot be "
 
125
                             "read without data loss.",
 
126
                             str(error))
 
127
 
 
128
    def test_jail_break(self):
 
129
        error = errors.JailBreak("some url")
 
130
        self.assertEqualDiff("An attempt to access a url outside the server"
 
131
                             " jail was made: 'some url'.",
 
132
                             str(error))
 
133
 
 
134
    def test_lock_active(self):
 
135
        error = errors.LockActive("lock description")
 
136
        self.assertEqualDiff("The lock for 'lock description' is in use and "
 
137
                             "cannot be broken.",
 
138
                             str(error))
 
139
 
 
140
    def test_lock_corrupt(self):
 
141
        error = errors.LockCorrupt("corruption info")
 
142
        self.assertEqualDiff("Lock is apparently held, but corrupted: "
 
143
                             "corruption info\n"
 
144
                             "Use 'brz break-lock' to clear it",
 
145
                             str(error))
 
146
 
 
147
    def test_medium_not_connected(self):
 
148
        error = errors.MediumNotConnected("a medium")
 
149
        self.assertEqualDiff(
 
150
            "The medium 'a medium' is not connected.", str(error))
 
151
 
 
152
    def test_no_smart_medium(self):
 
153
        error = errors.NoSmartMedium("a transport")
 
154
        self.assertEqualDiff("The transport 'a transport' cannot tunnel the "
 
155
                             "smart protocol.",
 
156
                             str(error))
 
157
 
 
158
    def test_no_such_id(self):
 
159
        error = errors.NoSuchId("atree", "anid")
 
160
        self.assertEqualDiff("The file id \"anid\" is not present in the tree "
 
161
                             "atree.",
 
162
                             str(error))
 
163
 
 
164
    def test_no_such_revision_in_tree(self):
 
165
        error = errors.NoSuchRevisionInTree("atree", "anid")
 
166
        self.assertEqualDiff("The revision id {anid} is not present in the"
 
167
                             " tree atree.", str(error))
 
168
        self.assertIsInstance(error, errors.NoSuchRevision)
 
169
 
 
170
    def test_not_stacked(self):
 
171
        error = errors.NotStacked('a branch')
 
172
        self.assertEqualDiff("The branch 'a branch' is not stacked.",
 
173
                             str(error))
 
174
 
 
175
    def test_not_write_locked(self):
 
176
        error = errors.NotWriteLocked('a thing to repr')
 
177
        self.assertEqualDiff("'a thing to repr' is not write locked but needs "
 
178
                             "to be.",
 
179
                             str(error))
 
180
 
 
181
    def test_lock_failed(self):
 
182
        error = errors.LockFailed(
 
183
            'http://canonical.com/', 'readonly transport')
 
184
        self.assertEqualDiff("Cannot lock http://canonical.com/: readonly transport",
 
185
                             str(error))
 
186
        self.assertFalse(error.internal_error)
 
187
 
 
188
    def test_too_many_concurrent_requests(self):
 
189
        error = errors.TooManyConcurrentRequests("a medium")
 
190
        self.assertEqualDiff("The medium 'a medium' has reached its concurrent "
 
191
                             "request limit. Be sure to finish_writing and finish_reading on "
 
192
                             "the currently open request.",
 
193
                             str(error))
 
194
 
 
195
    def test_unavailable_representation(self):
 
196
        error = errors.UnavailableRepresentation(
 
197
            ('key',), "mpdiff", "fulltext")
 
198
        self.assertEqualDiff("The encoding 'mpdiff' is not available for key "
 
199
                             "('key',) which is encoded as 'fulltext'.",
 
200
                             str(error))
 
201
 
 
202
    def test_unstackable_location(self):
 
203
        error = errors.UnstackableLocationError('foo', 'bar')
 
204
        self.assertEqualDiff("The branch 'foo' cannot be stacked on 'bar'.",
 
205
                             str(error))
 
206
 
 
207
    def test_unstackable_repository_format(self):
 
208
        format = u'foo'
 
209
        url = "/foo"
 
210
        error = errors.UnstackableRepositoryFormat(format, url)
 
211
        self.assertEqualDiff(
 
212
            "The repository '/foo'(foo) is not a stackable format. "
 
213
            "You will need to upgrade the repository to permit branch stacking.",
 
214
            str(error))
 
215
 
 
216
    def test_up_to_date(self):
 
217
        error = errors.UpToDateFormat("someformat")
 
218
        self.assertEqualDiff(
 
219
            "The branch format someformat is already at the most "
 
220
            "recent format.", str(error))
 
221
 
 
222
    def test_read_error(self):
 
223
        # a unicode path to check that %r is being used.
 
224
        path = u'a path'
 
225
        error = errors.ReadError(path)
 
226
        self.assertContainsRe(str(error), "^Error reading from u?'a path'.$")
 
227
 
 
228
    def test_bzrerror_from_literal_string(self):
 
229
        # Some code constructs BzrError from a literal string, in which case
 
230
        # no further formatting is done.  (I'm not sure raising the base class
 
231
        # is a great idea, but if the exception is not intended to be caught
 
232
        # perhaps no more is needed.)
 
233
        try:
 
234
            raise errors.BzrError('this is my errors; %d is not expanded')
 
235
        except errors.BzrError as e:
 
236
            self.assertEqual('this is my errors; %d is not expanded', str(e))
 
237
 
 
238
    def test_reading_completed(self):
 
239
        error = errors.ReadingCompleted("a request")
 
240
        self.assertEqualDiff("The MediumRequest 'a request' has already had "
 
241
                             "finish_reading called upon it - the request has been completed and"
 
242
                             " no more data may be read.",
 
243
                             str(error))
 
244
 
 
245
    def test_writing_completed(self):
 
246
        error = errors.WritingCompleted("a request")
 
247
        self.assertEqualDiff("The MediumRequest 'a request' has already had "
 
248
                             "finish_writing called upon it - accept bytes may not be called "
 
249
                             "anymore.",
 
250
                             str(error))
 
251
 
 
252
    def test_writing_not_completed(self):
 
253
        error = errors.WritingNotComplete("a request")
 
254
        self.assertEqualDiff("The MediumRequest 'a request' has not has "
 
255
                             "finish_writing called upon it - until the write phase is complete"
 
256
                             " no data may be read.",
 
257
                             str(error))
 
258
 
 
259
    def test_transport_not_possible(self):
 
260
        error = errors.TransportNotPossible('readonly', 'original error')
 
261
        self.assertEqualDiff('Transport operation not possible:'
 
262
                             ' readonly original error', str(error))
 
263
 
 
264
    def assertSocketConnectionError(self, expected, *args, **kwargs):
 
265
        """Check the formatting of a SocketConnectionError exception"""
 
266
        e = errors.SocketConnectionError(*args, **kwargs)
 
267
        self.assertEqual(expected, str(e))
 
268
 
 
269
    def test_socket_connection_error(self):
 
270
        """Test the formatting of SocketConnectionError"""
 
271
 
 
272
        # There should be a default msg about failing to connect
 
273
        # we only require a host name.
 
274
        self.assertSocketConnectionError(
 
275
            'Failed to connect to ahost',
 
276
            'ahost')
 
277
 
 
278
        # If port is None, we don't put :None
 
279
        self.assertSocketConnectionError(
 
280
            'Failed to connect to ahost',
 
281
            'ahost', port=None)
 
282
        # But if port is supplied we include it
 
283
        self.assertSocketConnectionError(
 
284
            'Failed to connect to ahost:22',
 
285
            'ahost', port=22)
 
286
 
 
287
        # We can also supply extra information about the error
 
288
        # with or without a port
 
289
        self.assertSocketConnectionError(
 
290
            'Failed to connect to ahost:22; bogus error',
 
291
            'ahost', port=22, orig_error='bogus error')
 
292
        self.assertSocketConnectionError(
 
293
            'Failed to connect to ahost; bogus error',
 
294
            'ahost', orig_error='bogus error')
 
295
        # An exception object can be passed rather than a string
 
296
        orig_error = ValueError('bad value')
 
297
        self.assertSocketConnectionError(
 
298
            'Failed to connect to ahost; %s' % (str(orig_error),),
 
299
            host='ahost', orig_error=orig_error)
 
300
 
 
301
        # And we can supply a custom failure message
 
302
        self.assertSocketConnectionError(
 
303
            'Unable to connect to ssh host ahost:444; my_error',
 
304
            host='ahost', port=444, msg='Unable to connect to ssh host',
 
305
            orig_error='my_error')
 
306
 
 
307
    def test_target_not_branch(self):
 
308
        """Test the formatting of TargetNotBranch."""
 
309
        error = errors.TargetNotBranch('foo')
 
310
        self.assertEqual(
 
311
            "Your branch does not have all of the revisions required in "
 
312
            "order to merge this merge directive and the target "
 
313
            "location specified in the merge directive is not a branch: "
 
314
            "foo.", str(error))
 
315
 
 
316
    def test_unexpected_smart_server_response(self):
 
317
        e = errors.UnexpectedSmartServerResponse(('not yes',))
 
318
        self.assertEqual(
 
319
            "Could not understand response from smart server: ('not yes',)",
 
320
            str(e))
 
321
 
 
322
    def test_unknown_container_format(self):
 
323
        """Test the formatting of UnknownContainerFormatError."""
 
324
        e = errors.UnknownContainerFormatError('bad format string')
 
325
        self.assertEqual(
 
326
            "Unrecognised container format: 'bad format string'",
 
327
            str(e))
 
328
 
 
329
    def test_unexpected_end_of_container(self):
 
330
        """Test the formatting of UnexpectedEndOfContainerError."""
 
331
        e = errors.UnexpectedEndOfContainerError()
 
332
        self.assertEqual(
 
333
            "Unexpected end of container stream", str(e))
 
334
 
 
335
    def test_unknown_record_type(self):
 
336
        """Test the formatting of UnknownRecordTypeError."""
 
337
        e = errors.UnknownRecordTypeError("X")
 
338
        self.assertEqual(
 
339
            "Unknown record type: 'X'",
 
340
            str(e))
 
341
 
 
342
    def test_invalid_record(self):
 
343
        """Test the formatting of InvalidRecordError."""
 
344
        e = errors.InvalidRecordError("xxx")
 
345
        self.assertEqual(
 
346
            "Invalid record: xxx",
 
347
            str(e))
 
348
 
 
349
    def test_container_has_excess_data(self):
 
350
        """Test the formatting of ContainerHasExcessDataError."""
 
351
        e = errors.ContainerHasExcessDataError("excess bytes")
 
352
        self.assertEqual(
 
353
            "Container has data after end marker: 'excess bytes'",
 
354
            str(e))
 
355
 
 
356
    def test_duplicate_record_name_error(self):
 
357
        """Test the formatting of DuplicateRecordNameError."""
 
358
        e = errors.DuplicateRecordNameError(b"n\xc3\xa5me")
 
359
        self.assertEqual(
 
360
            u"Container has multiple records with the same name: n\xe5me",
 
361
            str(e))
 
362
 
 
363
    def test_check_error(self):
 
364
        e = errors.BzrCheckError('example check failure')
 
365
        self.assertEqual(
 
366
            "Internal check failed: example check failure",
 
367
            str(e))
 
368
        self.assertTrue(e.internal_error)
 
369
 
 
370
    def test_repository_data_stream_error(self):
 
371
        """Test the formatting of RepositoryDataStreamError."""
 
372
        e = errors.RepositoryDataStreamError(u"my reason")
 
373
        self.assertEqual(
 
374
            "Corrupt or incompatible data stream: my reason", str(e))
 
375
 
 
376
    def test_immortal_pending_deletion_message(self):
 
377
        err = errors.ImmortalPendingDeletion('foo')
 
378
        self.assertEqual(
 
379
            "Unable to delete transform temporary directory foo.  "
 
380
            "Please examine foo to see if it contains any files "
 
381
            "you wish to keep, and delete it when you are done.",
 
382
            str(err))
 
383
 
 
384
    def test_invalid_url_join(self):
 
385
        """Test the formatting of InvalidURLJoin."""
 
386
        e = urlutils.InvalidURLJoin('Reason', 'base path', ('args',))
 
387
        self.assertEqual(
 
388
            "Invalid URL join request: Reason: 'base path' + ('args',)",
 
389
            str(e))
 
390
 
 
391
    def test_unable_encode_path(self):
 
392
        err = errors.UnableEncodePath('foo', 'executable')
 
393
        self.assertEqual("Unable to encode executable path 'foo' in "
 
394
                         "user encoding " + osutils.get_user_encoding(),
 
395
                         str(err))
 
396
 
 
397
    def test_unknown_format(self):
 
398
        err = errors.UnknownFormatError('bar', kind='foo')
 
399
        self.assertEqual("Unknown foo format: 'bar'", str(err))
 
400
 
 
401
    def test_tip_change_rejected(self):
 
402
        err = errors.TipChangeRejected(u'Unicode message\N{INTERROBANG}')
 
403
        self.assertEqual(
 
404
            u'Tip change rejected: Unicode message\N{INTERROBANG}',
 
405
            str(err))
 
406
 
 
407
    def test_error_from_smart_server(self):
 
408
        error_tuple = ('error', 'tuple')
 
409
        err = errors.ErrorFromSmartServer(error_tuple)
 
410
        self.assertEqual(
 
411
            "Error received from smart server: ('error', 'tuple')", str(err))
 
412
 
 
413
    def test_untranslateable_error_from_smart_server(self):
 
414
        error_tuple = ('error', 'tuple')
 
415
        orig_err = errors.ErrorFromSmartServer(error_tuple)
 
416
        err = errors.UnknownErrorFromSmartServer(orig_err)
 
417
        self.assertEqual(
 
418
            "Server sent an unexpected error: ('error', 'tuple')", str(err))
 
419
 
 
420
    def test_smart_message_handler_error(self):
 
421
        # Make an exc_info tuple.
 
422
        try:
 
423
            raise Exception("example error")
 
424
        except Exception:
 
425
            err = errors.SmartMessageHandlerError(sys.exc_info())
 
426
        # GZ 2010-11-08: Should not store exc_info in exception instances.
 
427
        try:
 
428
            self.assertStartsWith(
 
429
                str(err), "The message handler raised an exception:\n")
 
430
            self.assertEndsWith(str(err), "Exception: example error\n")
 
431
        finally:
 
432
            del err
 
433
 
 
434
    def test_unresumable_write_group(self):
 
435
        repo = "dummy repo"
 
436
        wg_tokens = ['token']
 
437
        reason = "a reason"
 
438
        err = errors.UnresumableWriteGroup(repo, wg_tokens, reason)
 
439
        self.assertEqual(
 
440
            "Repository dummy repo cannot resume write group "
 
441
            "['token']: a reason", str(err))
 
442
 
 
443
    def test_unsuspendable_write_group(self):
 
444
        repo = "dummy repo"
 
445
        err = errors.UnsuspendableWriteGroup(repo)
 
446
        self.assertEqual(
 
447
            'Repository dummy repo cannot suspend a write group.', str(err))
 
448
 
 
449
    def test_not_branch_no_args(self):
 
450
        err = errors.NotBranchError('path')
 
451
        self.assertEqual('Not a branch: "path".', str(err))
 
452
 
 
453
    def test_not_branch_bzrdir_with_recursive_not_branch_error(self):
 
454
        class FakeBzrDir(object):
 
455
            def open_repository(self):
 
456
                # str() on the NotBranchError will trigger a call to this,
 
457
                # which in turn will another, identical NotBranchError.
 
458
                raise errors.NotBranchError('path', controldir=FakeBzrDir())
 
459
        err = errors.NotBranchError('path', controldir=FakeBzrDir())
 
460
        self.assertEqual('Not a branch: "path": NotBranchError.', str(err))
 
461
 
 
462
    def test_recursive_bind(self):
 
463
        error = errors.RecursiveBind('foo_bar_branch')
 
464
        msg = ('Branch "foo_bar_branch" appears to be bound to itself. '
 
465
               'Please use `brz unbind` to fix.')
 
466
        self.assertEqualDiff(msg, str(error))
 
467
 
 
468
    def test_retry_with_new_packs(self):
 
469
        fake_exc_info = ('{exc type}', '{exc value}', '{exc traceback}')
 
470
        error = errors.RetryWithNewPacks(
 
471
            '{context}', reload_occurred=False, exc_info=fake_exc_info)
 
472
        self.assertEqual(
 
473
            'Pack files have changed, reload and retry. context: '
 
474
            '{context} {exc value}', str(error))
 
475
 
 
476
 
 
477
class PassThroughError(errors.BzrError):
 
478
 
 
479
    _fmt = """Pass through %(foo)s and %(bar)s"""
 
480
 
 
481
    def __init__(self, foo, bar):
 
482
        errors.BzrError.__init__(self, foo=foo, bar=bar)
 
483
 
 
484
 
 
485
class ErrorWithBadFormat(errors.BzrError):
 
486
 
 
487
    _fmt = """One format specifier: %(thing)s"""
 
488
 
 
489
 
 
490
class ErrorWithNoFormat(errors.BzrError):
 
491
    __doc__ = """This class has a docstring but no format string."""
 
492
 
 
493
 
 
494
class TestErrorFormatting(tests.TestCase):
 
495
 
 
496
    def test_always_str(self):
 
497
        e = PassThroughError(u'\xb5', 'bar')
 
498
        self.assertIsInstance(e.__str__(), str)
 
499
        # In Python 2 str(foo) *must* return a real byte string
 
500
        # not a Unicode string. The following line would raise a
 
501
        # Unicode error, because it tries to call str() on the string
 
502
        # returned from e.__str__(), and it has non ascii characters
 
503
        s = str(e)
 
504
        self.assertEqual('Pass through \xb5 and bar', s)
 
505
 
 
506
    def test_missing_format_string(self):
 
507
        e = ErrorWithNoFormat(param='randomvalue')
 
508
        self.assertStartsWith(str(e),
 
509
                              "Unprintable exception ErrorWithNoFormat")
 
510
 
 
511
    def test_mismatched_format_args(self):
 
512
        # Even though ErrorWithBadFormat's format string does not match the
 
513
        # arguments we constructing it with, we can still stringify an instance
 
514
        # of this exception. The resulting string will say its unprintable.
 
515
        e = ErrorWithBadFormat(not_thing='x')
 
516
        self.assertStartsWith(
 
517
            str(e), 'Unprintable exception ErrorWithBadFormat')
 
518
 
 
519
    def test_cannot_bind_address(self):
 
520
        # see <https://bugs.launchpad.net/bzr/+bug/286871>
 
521
        e = errors.CannotBindAddress('example.com', 22,
 
522
                                     socket.error(13, 'Permission denied'))
 
523
        self.assertContainsRe(
 
524
            str(e),
 
525
            r'Cannot bind address "example\.com:22":.*Permission denied')
 
526
 
 
527
    def test_transform_rename_failed(self):
 
528
        e = errors.TransformRenameFailed(u"from", u"to", "readonly file", 2)
 
529
        self.assertEqual(
 
530
            u"Failed to rename from to to: readonly file",
 
531
            str(e))
 
532
 
 
533
 
 
534
class TestErrorsUsingTransport(tests.TestCaseWithMemoryTransport):
 
535
    """Tests for errors that need to use a branch or repo."""
 
536
 
 
537
    def test_no_public_branch(self):
 
538
        b = self.make_branch('.')
 
539
        error = errors.NoPublicBranch(b)
 
540
        url = urlutils.unescape_for_display(b.base, 'ascii')
 
541
        self.assertEqualDiff(
 
542
            'There is no public branch set for "%s".' % url, str(error))
26
543
 
27
544
    def test_no_repo(self):
28
 
        dir = bzrdir.BzrDir.create(self.get_url())
 
545
        dir = controldir.ControlDir.create(self.get_url())
29
546
        error = errors.NoRepositoryPresent(dir)
30
 
        self.assertNotEqual(-1, str(error).find(repr(dir.transport.clone('..').base)))
31
 
        self.assertEqual(-1, str(error).find(repr(dir.transport.base)))
32
 
 
33
 
    def test_up_to_date(self):
34
 
        error = errors.UpToDateFormat(bzrdir.BzrDirFormat4())
35
 
        self.assertEqualDiff("The branch format Bazaar-NG branch, "
36
 
                             "format 0.0.4 is already at the most "
37
 
                             "recent format.",
38
 
                             str(error))
 
547
        self.assertNotEqual(-1,
 
548
                            str(error).find((dir.transport.clone('..').base)))
 
549
        self.assertEqual(-1, str(error).find((dir.transport.base)))
39
550
 
40
551
    def test_corrupt_repository(self):
41
552
        repo = self.make_repository('.')
42
553
        error = errors.CorruptRepository(repo)
43
554
        self.assertEqualDiff("An error has been detected in the repository %s.\n"
44
 
                             "Please run bzr reconcile on this repository." %
45
 
                             repo.bzrdir.root_transport.base,
 
555
                             "Please run brz reconcile on this repository." %
 
556
                             repo.controldir.root_transport.base,
46
557
                             str(error))
 
558
 
 
559
    def test_not_branch_bzrdir_with_repo(self):
 
560
        controldir = self.make_repository('repo').controldir
 
561
        err = errors.NotBranchError('path', controldir=controldir)
 
562
        self.assertEqual(
 
563
            'Not a branch: "path": location is a repository.', str(err))
 
564
 
 
565
    def test_not_branch_bzrdir_without_repo(self):
 
566
        controldir = self.make_controldir('bzrdir')
 
567
        err = errors.NotBranchError('path', controldir=controldir)
 
568
        self.assertEqual('Not a branch: "path".', str(err))
 
569
 
 
570
    def test_not_branch_laziness(self):
 
571
        real_bzrdir = self.make_controldir('path')
 
572
 
 
573
        class FakeBzrDir(object):
 
574
            def __init__(self):
 
575
                self.calls = []
 
576
 
 
577
            def open_repository(self):
 
578
                self.calls.append('open_repository')
 
579
                raise errors.NoRepositoryPresent(real_bzrdir)
 
580
        fake_bzrdir = FakeBzrDir()
 
581
        err = errors.NotBranchError('path', controldir=fake_bzrdir)
 
582
        self.assertEqual([], fake_bzrdir.calls)
 
583
        str(err)
 
584
        self.assertEqual(['open_repository'], fake_bzrdir.calls)
 
585
        # Stringifying twice doesn't try to open a repository twice.
 
586
        str(err)
 
587
        self.assertEqual(['open_repository'], fake_bzrdir.calls)