/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.18.22 by Martin Pool
merge bzr.dev
1
# Copyright (C) 2006, 2007 Canonical Ltd
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
2
#   Authors: Robert Collins <robert.collins@canonical.com>
2018.18.22 by Martin Pool
merge bzr.dev
3
#            and others
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
"""Tests for the formatting and construction of errors."""
20
1948.1.6 by John Arbash Meinel
Make BzrNewError always return a str object
21
from bzrlib import (
22
    bzrdir,
23
    errors,
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
24
    symbol_versioning,
1948.1.6 by John Arbash Meinel
Make BzrNewError always return a str object
25
    )
26
from bzrlib.tests import TestCase, TestCaseWithTransport
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
27
28
29
class TestErrors(TestCaseWithTransport):
30
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
31
    def test_disabled_method(self):
32
        error = errors.DisabledMethod("class name")
33
        self.assertEqualDiff(
34
            "The smart server method 'class name' is disabled.", str(error))
35
2255.7.16 by John Arbash Meinel
Make sure adding a duplicate file_id raises DuplicateFileId.
36
    def test_duplicate_file_id(self):
37
        error = errors.DuplicateFileId('a_file_id', 'foo')
38
        self.assertEqualDiff('File id {a_file_id} already exists in inventory'
39
                             ' as foo', str(error))
40
2432.1.19 by Robert Collins
Ensure each HelpIndex has a unique prefix.
41
    def test_duplicate_help_prefix(self):
42
        error = errors.DuplicateHelpPrefix('foo')
43
        self.assertEqualDiff('The prefix foo is in the help search path twice.',
44
            str(error))
45
2550.2.3 by Robert Collins
Add require_api API.
46
    def test_incompatibleAPI(self):
47
        error = errors.IncompatibleAPI("module", (1, 2, 3), (4, 5, 6), (7, 8, 9))
48
        self.assertEqualDiff(
49
            'The API for "module" is not compatible with "(1, 2, 3)". '
50
            'It supports versions "(4, 5, 6)" to "(7, 8, 9)".',
51
            str(error))
52
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
53
    def test_in_process_transport(self):
54
        error = errors.InProcessTransport('fpp')
55
        self.assertEqualDiff(
56
            "The transport 'fpp' is only accessible within this process.",
57
            str(error))
58
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
59
    def test_inventory_modified(self):
60
        error = errors.InventoryModified("a tree to be repred")
61
        self.assertEqualDiff("The current inventory for the tree 'a tree to "
62
            "be repred' has been modified, so a clean inventory cannot be "
63
            "read without data loss.",
64
            str(error))
65
2116.3.1 by John Arbash Meinel
Cleanup error tests
66
    def test_install_failed(self):
67
        error = errors.InstallFailed(['rev-one'])
68
        self.assertEqual("Could not install revisions:\nrev-one", str(error))
69
        error = errors.InstallFailed(['rev-one', 'rev-two'])
70
        self.assertEqual("Could not install revisions:\nrev-one, rev-two",
71
                         str(error))
72
        error = errors.InstallFailed([None])
73
        self.assertEqual("Could not install revisions:\nNone", str(error))
74
2255.2.145 by Robert Collins
Support unbreakable locks for trees.
75
    def test_lock_active(self):
76
        error = errors.LockActive("lock description")
77
        self.assertEqualDiff("The lock for 'lock description' is in use and "
78
            "cannot be broken.",
79
            str(error))
80
2535.3.4 by Andrew Bennetts
Simple implementation of Knit.insert_data_stream.
81
    def test_knit_data_stream_incompatible(self):
82
        error = errors.KnitDataStreamIncompatible(
83
            'stream format', 'target format')
84
        self.assertEqual('Cannot insert knit data stream of format '
85
                         '"stream format" into knit of format '
86
                         '"target format".', str(error))
87
2171.1.1 by John Arbash Meinel
Knit index files should ignore empty indexes rather than consider them corrupt.
88
    def test_knit_header_error(self):
89
        error = errors.KnitHeaderError('line foo\n', 'path/to/file')
90
        self.assertEqual("Knit header error: 'line foo\\n' unexpected"
2745.3.2 by Daniel Watkins
Updated tests to reflect new error text.
91
                         " for file \"path/to/file\".", str(error))
2171.1.1 by John Arbash Meinel
Knit index files should ignore empty indexes rather than consider them corrupt.
92
2196.2.5 by John Arbash Meinel
Add an exception class when the knit index storage method is unknown, and properly test for it
93
    def test_knit_index_unknown_method(self):
94
        error = errors.KnitIndexUnknownMethod('http://host/foo.kndx',
95
                                              ['bad', 'no-eol'])
96
        self.assertEqual("Knit index http://host/foo.kndx does not have a"
97
                         " known method in options: ['bad', 'no-eol']",
98
                         str(error))
99
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
100
    def test_medium_not_connected(self):
101
        error = errors.MediumNotConnected("a medium")
102
        self.assertEqualDiff(
103
            "The medium 'a medium' is not connected.", str(error))
104
        
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
105
    def test_no_repo(self):
106
        dir = bzrdir.BzrDir.create(self.get_url())
107
        error = errors.NoRepositoryPresent(dir)
1740.5.6 by Martin Pool
Clean up many exception classes.
108
        self.assertNotEqual(-1, str(error).find((dir.transport.clone('..').base)))
109
        self.assertEqual(-1, str(error).find((dir.transport.base)))
1988.2.1 by Robert Collins
WorkingTree has a new api ``unversion`` which allow the unversioning of
110
        
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
111
    def test_no_smart_medium(self):
112
        error = errors.NoSmartMedium("a transport")
113
        self.assertEqualDiff("The transport 'a transport' cannot tunnel the "
114
            "smart protocol.",
115
            str(error))
116
2432.1.4 by Robert Collins
Add an explicit error for missing help topics.
117
    def test_no_help_topic(self):
118
        error = errors.NoHelpTopic("topic")
119
        self.assertEqualDiff("No help could be found for 'topic'. "
120
            "Please use 'bzr help topics' to obtain a list of topics.",
121
            str(error))
122
1988.2.1 by Robert Collins
WorkingTree has a new api ``unversion`` which allow the unversioning of
123
    def test_no_such_id(self):
124
        error = errors.NoSuchId("atree", "anid")
2745.3.2 by Daniel Watkins
Updated tests to reflect new error text.
125
        self.assertEqualDiff("The file id \"anid\" is not present in the tree "
2745.3.3 by Daniel Watkins
Changed to remove need for escaping of quotes.
126
            "atree.",
1988.2.1 by Robert Collins
WorkingTree has a new api ``unversion`` which allow the unversioning of
127
            str(error))
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
128
1908.11.1 by Robert Collins
Add a new method ``Tree.revision_tree`` which allows access to cached
129
    def test_no_such_revision_in_tree(self):
130
        error = errors.NoSuchRevisionInTree("atree", "anid")
2745.3.3 by Daniel Watkins
Changed to remove need for escaping of quotes.
131
        self.assertEqualDiff("The revision id {anid} is not present in the"
132
                             " tree atree.", str(error))
1908.11.1 by Robert Collins
Add a new method ``Tree.revision_tree`` which allows access to cached
133
        self.assertIsInstance(error, errors.NoSuchRevision)
134
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
135
    def test_not_write_locked(self):
136
        error = errors.NotWriteLocked('a thing to repr')
137
        self.assertEqualDiff("'a thing to repr' is not write locked but needs "
138
            "to be.",
139
            str(error))
140
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
141
    def test_read_only_lock_error(self):
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
142
        error = self.applyDeprecated(symbol_versioning.zero_ninetytwo,
143
            errors.ReadOnlyLockError, 'filename', 'error message')
2353.3.10 by John Arbash Meinel
Cleanup errors, and change ReadOnlyLockError to pass around more details.
144
        self.assertEqualDiff("Cannot acquire write lock on filename."
145
                             " error message", str(error))
146
2872.5.1 by Martin Pool
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).
147
    def test_lock_failed(self):
148
        error = errors.LockFailed('http://canonical.com/', 'readonly transport')
149
        self.assertEqualDiff("Cannot lock http://canonical.com/: readonly transport",
150
            str(error))
151
        self.assertFalse(error.internal_error)
152
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
153
    def test_too_many_concurrent_requests(self):
154
        error = errors.TooManyConcurrentRequests("a medium")
155
        self.assertEqualDiff("The medium 'a medium' has reached its concurrent "
156
            "request limit. Be sure to finish_writing and finish_reading on "
2018.5.134 by Andrew Bennetts
Fix the TooManyConcurrentRequests error message.
157
            "the currently open request.",
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
158
            str(error))
159
2245.1.3 by Robert Collins
Add install_hook to the BranchHooks class as the official means for installing a hook.
160
    def test_unknown_hook(self):
161
        error = errors.UnknownHook("branch", "foo")
162
        self.assertEqualDiff("The branch hook 'foo' is unknown in this version"
163
            " of bzrlib.",
164
            str(error))
165
        error = errors.UnknownHook("tree", "bar")
166
        self.assertEqualDiff("The tree hook 'bar' is unknown in this version"
167
            " of bzrlib.",
168
            str(error))
169
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
170
    def test_up_to_date(self):
171
        error = errors.UpToDateFormat(bzrdir.BzrDirFormat4())
1534.5.9 by Robert Collins
Advise users running upgrade on a checkout to also run it on the branch.
172
        self.assertEqualDiff("The branch format Bazaar-NG branch, "
173
                             "format 0.0.4 is already at the most "
174
                             "recent format.",
175
                             str(error))
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
176
177
    def test_corrupt_repository(self):
178
        repo = self.make_repository('.')
179
        error = errors.CorruptRepository(repo)
180
        self.assertEqualDiff("An error has been detected in the repository %s.\n"
181
                             "Please run bzr reconcile on this repository." %
182
                             repo.bzrdir.root_transport.base,
183
                             str(error))
1948.1.6 by John Arbash Meinel
Make BzrNewError always return a str object
184
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
185
    def test_read_error(self):
186
        # a unicode path to check that %r is being used.
187
        path = u'a path'
188
        error = errors.ReadError(path)
189
        self.assertEqualDiff("Error reading from u'a path'.", str(error))
190
2592.1.7 by Robert Collins
A validate that goes boom.
191
    def test_bad_index_format_signature(self):
192
        error = errors.BadIndexFormatSignature("foo", "bar")
193
        self.assertEqual("foo is not an index of type bar.",
194
            str(error))
2052.6.2 by Robert Collins
Merge bzr.dev.
195
2592.1.11 by Robert Collins
Detect truncated indices.
196
    def test_bad_index_data(self):
197
        error = errors.BadIndexData("foo")
198
        self.assertEqual("Error in data for index foo.",
199
            str(error))
200
2592.1.15 by Robert Collins
Detect duplicate key insertion.
201
    def test_bad_index_duplicate_key(self):
202
        error = errors.BadIndexDuplicateKey("foo", "bar")
203
        self.assertEqual("The key 'foo' is already in index 'bar'.",
204
            str(error))
205
2592.1.12 by Robert Collins
Handle basic node adds.
206
    def test_bad_index_key(self):
207
        error = errors.BadIndexKey("foo")
208
        self.assertEqual("The key 'foo' is not a valid key.",
209
            str(error))
210
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
211
    def test_bad_index_options(self):
212
        error = errors.BadIndexOptions("foo")
213
        self.assertEqual("Could not parse options for index foo.",
214
            str(error))
215
2592.1.12 by Robert Collins
Handle basic node adds.
216
    def test_bad_index_value(self):
217
        error = errors.BadIndexValue("foo")
218
        self.assertEqual("The value 'foo' is not a valid value.",
219
            str(error))
220
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
221
    def test_bzrnewerror_is_deprecated(self):
222
        class DeprecatedError(errors.BzrNewError):
223
            pass
2067.3.6 by Martin Pool
Update deprecation version
224
        self.callDeprecated(['BzrNewError was deprecated in bzr 0.13; '
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
225
             'please convert DeprecatedError to use BzrError instead'],
226
            DeprecatedError)
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, e:
236
            self.assertEqual('this is my errors; %d is not expanded', str(e))
237
2018.2.4 by Robert Collins
separate out the client medium from the client encoding protocol for the smart server.
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
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
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))
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
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
2376.4.26 by Jonathan Lange
Tests for MalformedBugIdentifier and new error UnknownBugTrackerAbbreviation.
307
    def test_malformed_bug_identifier(self):
308
        """Test the formatting of MalformedBugIdentifier."""
309
        error = errors.MalformedBugIdentifier('bogus', 'reason for bogosity')
310
        self.assertEqual(
311
            "Did not understand bug identifier bogus: reason for bogosity",
312
            str(error))
313
314
    def test_unknown_bug_tracker_abbreviation(self):
315
        """Test the formatting of UnknownBugTrackerAbbreviation."""
2376.4.27 by Jonathan Lange
Include branch information in UnknownBugTrackerAbbreviation
316
        branch = self.make_branch('some_branch')
317
        error = errors.UnknownBugTrackerAbbreviation('xxx', branch)
2376.4.26 by Jonathan Lange
Tests for MalformedBugIdentifier and new error UnknownBugTrackerAbbreviation.
318
        self.assertEqual(
2376.4.27 by Jonathan Lange
Include branch information in UnknownBugTrackerAbbreviation
319
            "Cannot find registered bug tracker called xxx on %s" % branch,
2376.4.26 by Jonathan Lange
Tests for MalformedBugIdentifier and new error UnknownBugTrackerAbbreviation.
320
            str(error))
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
321
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
322
    def test_unexpected_smart_server_response(self):
323
        e = errors.UnexpectedSmartServerResponse(('not yes',))
324
        self.assertEqual(
325
            "Could not understand response from smart server: ('not yes',)",
326
            str(e))
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
327
2506.2.1 by Andrew Bennetts
Start implementing container format reading and writing.
328
    def test_unknown_container_format(self):
329
        """Test the formatting of UnknownContainerFormatError."""
330
        e = errors.UnknownContainerFormatError('bad format string')
331
        self.assertEqual(
332
            "Unrecognised container format: 'bad format string'",
333
            str(e))
334
335
    def test_unexpected_end_of_container(self):
336
        """Test the formatting of UnexpectedEndOfContainerError."""
337
        e = errors.UnexpectedEndOfContainerError()
338
        self.assertEqual(
339
            "Unexpected end of container stream", str(e))
340
341
    def test_unknown_record_type(self):
342
        """Test the formatting of UnknownRecordTypeError."""
343
        e = errors.UnknownRecordTypeError("X")
344
        self.assertEqual(
345
            "Unknown record type: 'X'",
346
            str(e))
347
2506.3.1 by Andrew Bennetts
More progress:
348
    def test_invalid_record(self):
349
        """Test the formatting of InvalidRecordError."""
350
        e = errors.InvalidRecordError("xxx")
351
        self.assertEqual(
352
            "Invalid record: xxx",
353
            str(e))
354
2506.2.6 by Andrew Bennetts
Add validate method to ContainerReader and BytesRecordReader.
355
    def test_container_has_excess_data(self):
356
        """Test the formatting of ContainerHasExcessDataError."""
357
        e = errors.ContainerHasExcessDataError("excess bytes")
358
        self.assertEqual(
359
            "Container has data after end marker: 'excess bytes'",
360
            str(e))
361
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
362
    def test_duplicate_record_name_error(self):
363
        """Test the formatting of DuplicateRecordNameError."""
364
        e = errors.DuplicateRecordNameError(u"n\xe5me".encode('utf-8'))
365
        self.assertEqual(
2745.3.3 by Daniel Watkins
Changed to remove need for escaping of quotes.
366
            "Container has multiple records with the same name: n\xc3\xa5me",
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
367
            str(e))
2854.1.1 by Martin Pool
Fix "unprintable error" message for BzrCheckError and others
368
        
369
    def test_check_error(self):
370
        # This has a member called 'message', which is problematic in
371
        # python2.5 because that is a slot on the base Exception class
372
        e = errors.BzrCheckError('example check failure')
373
        self.assertEqual(
374
            "Internal check failed: example check failure",
375
            str(e))
376
        self.assertTrue(e.internal_error)
2506.6.1 by Andrew Bennetts
Return a callable instead of a str from read, and add more validation.
377
2535.3.40 by Andrew Bennetts
Tidy up more XXXs.
378
    def test_repository_data_stream_error(self):
379
        """Test the formatting of RepositoryDataStreamError."""
380
        e = errors.RepositoryDataStreamError(u"my reason")
381
        self.assertEqual(
382
            "Corrupt or incompatible data stream: my reason", str(e))
383
2978.2.1 by Alexander Belchenko
fix formatting of ImmortalPendingDeletion error message.
384
    def test_immortal_pending_deletion_message(self):
385
        err = errors.ImmortalPendingDeletion('foo')
386
        self.assertEquals(
387
            "Unable to delete transform temporary directory foo.  "
388
            "Please examine foo to see if it contains any files "
389
            "you wish to keep, and delete it when you are done.",
390
            str(err))
391
3006.2.2 by Alexander Belchenko
tests added.
392
    def test_unable_create_symlink(self):
393
        err = errors.UnableCreateSymlink()
394
        self.assertEquals(
395
            "Unable to create symlink on this platform",
396
            str(err))
397
        err = errors.UnableCreateSymlink(path=u'foo')
398
        self.assertEquals(
399
            "Unable to create symlink 'foo' on this platform",
400
            str(err))
401
        err = errors.UnableCreateSymlink(path=u'\xb5')
402
        self.assertEquals(
403
            "Unable to create symlink u'\\xb5' on this platform",
404
            str(err))
405
2116.3.1 by John Arbash Meinel
Cleanup error tests
406
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
407
class PassThroughError(errors.BzrError):
408
    
409
    _fmt = """Pass through %(foo)s and %(bar)s"""
2116.3.1 by John Arbash Meinel
Cleanup error tests
410
411
    def __init__(self, foo, bar):
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
412
        errors.BzrError.__init__(self, foo=foo, bar=bar)
413
414
415
class ErrorWithBadFormat(errors.BzrError):
416
417
    _fmt = """One format specifier: %(thing)s"""
418
419
420
class ErrorWithNoFormat(errors.BzrError):
421
    """This class has a docstring but no format string."""
2116.3.1 by John Arbash Meinel
Cleanup error tests
422
423
424
class TestErrorFormatting(TestCase):
425
    
426
    def test_always_str(self):
427
        e = PassThroughError(u'\xb5', 'bar')
428
        self.assertIsInstance(e.__str__(), str)
429
        # In Python str(foo) *must* return a real byte string
430
        # not a Unicode string. The following line would raise a
431
        # Unicode error, because it tries to call str() on the string
432
        # returned from e.__str__(), and it has non ascii characters
433
        s = str(e)
434
        self.assertEqual('Pass through \xc2\xb5 and bar', s)
435
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
436
    def test_missing_format_string(self):
437
        e = ErrorWithNoFormat(param='randomvalue')
2067.3.3 by Martin Pool
merge bzr.dev and reconcile several changes, also some test fixes
438
        s = self.callDeprecated(
439
                ['ErrorWithNoFormat uses its docstring as a format, it should use _fmt instead'],
440
                lambda x: str(x), e)
441
        ## s = str(e)
442
        self.assertEqual(s, 
443
                "This class has a docstring but no format string.")
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
444
2116.3.1 by John Arbash Meinel
Cleanup error tests
445
    def test_mismatched_format_args(self):
446
        # Even though ErrorWithBadFormat's format string does not match the
447
        # arguments we constructing it with, we can still stringify an instance
448
        # of this exception. The resulting string will say its unprintable.
449
        e = ErrorWithBadFormat(not_thing='x')
450
        self.assertStartsWith(
2067.3.1 by Martin Pool
Clean up BzrNewError, other exception classes and users.
451
            str(e), 'Unprintable exception ErrorWithBadFormat')