1
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
2
# See LICENSE for details.
6
Test cases for failure module.
13
from twisted.trial import unittest, util
15
from twisted.python import failure
18
from twisted.test import raiser
23
class BrokenStr(Exception):
28
def getDivisionFailure():
36
class FailureTestCase(unittest.TestCase):
38
def testFailAndTrap(self):
39
"""Trapping a failure."""
41
raise NotImplementedError('test')
44
error = f.trap(SystemExit, RuntimeError)
45
self.assertEquals(error, RuntimeError)
46
self.assertEquals(f.type, NotImplementedError)
48
def test_notTrapped(self):
49
"""Making sure trap doesn't trap what it shouldn't."""
54
self.assertRaises(failure.Failure, f.trap, OverflowError)
56
def testPrinting(self):
57
out = StringIO.StringIO()
62
f.printDetailedTraceback(out)
63
f.printBriefTraceback(out)
66
def testExplictPass(self):
68
f = failure.Failure(e)
70
self.assertEquals(f.value, e)
73
def _getInnermostFrameLine(self, f):
76
except ZeroDivisionError:
77
tb = traceback.extract_tb(sys.exc_info()[2])
81
"f.raiseException() didn't raise ZeroDivisionError!?")
84
def testRaiseExceptionWithTB(self):
85
f = getDivisionFailure()
86
innerline = self._getInnermostFrameLine(f)
87
self.assertEquals(innerline, '1/0')
90
def testLackOfTB(self):
91
f = getDivisionFailure()
93
innerline = self._getInnermostFrameLine(f)
94
self.assertEquals(innerline, '1/0')
96
testLackOfTB.todo = "the traceback is not preserved, exarkun said he'll try to fix this! god knows how"
99
_stringException = "bugger off"
100
def _getStringFailure(self):
102
raise self._stringException
104
f = failure.Failure()
107
def test_raiseStringExceptions(self):
108
# String exceptions used to totally bugged f.raiseException
109
f = self._getStringFailure()
113
self.assertEquals(sys.exc_info()[0], self._stringException)
115
raise AssertionError("Should have raised")
116
test_raiseStringExceptions.suppress = [
117
util.suppress(message='raising a string exception is deprecated')]
120
def test_printStringExceptions(self):
122
L{Failure.printTraceback} should write out stack and exception
123
information, even for string exceptions.
125
failure = self._getStringFailure()
126
output = StringIO.StringIO()
127
failure.printTraceback(file=output)
128
lines = output.getvalue().splitlines()
129
# The last line should be the value of the raised string
130
self.assertEqual(lines[-1], self._stringException)
132
test_printStringExceptions.suppress = [
133
util.suppress(message='raising a string exception is deprecated')]
135
if sys.version_info[:2] >= (2, 6):
136
skipMsg = ("String exceptions aren't supported anymore starting "
138
test_raiseStringExceptions.skip = skipMsg
139
test_printStringExceptions.skip = skipMsg
142
def testBrokenStr(self):
144
Formatting a traceback of a Failure which refers to an object
145
that has a broken __str__ implementation should not cause
146
getTraceback to raise an exception.
152
f = failure.Failure()
153
self.assertEquals(f.value, x)
157
self.fail("getTraceback() shouldn't raise an exception")
160
def testConstructionFails(self):
162
Creating a Failure with no arguments causes it to try to discover the
163
current interpreter exception state. If no such state exists, creating
164
the Failure should raise a synchronous exception.
166
self.assertRaises(failure.NoCurrentExceptionError, failure.Failure)
168
def test_getTracebackObject(self):
170
If the C{Failure} has not been cleaned, then C{getTracebackObject}
171
should return the traceback object that it was given in the
174
f = getDivisionFailure()
175
self.assertEqual(f.getTracebackObject(), f.tb)
177
def test_getTracebackObjectFromClean(self):
179
If the Failure has been cleaned, then C{getTracebackObject} should
180
return an object that looks the same to L{traceback.extract_tb}.
182
f = getDivisionFailure()
183
expected = traceback.extract_tb(f.getTracebackObject())
185
observed = traceback.extract_tb(f.getTracebackObject())
186
self.assertEqual(expected, observed)
188
def test_getTracebackObjectWithoutTraceback(self):
190
L{failure.Failure}s need not be constructed with traceback objects. If
191
a C{Failure} has no traceback information at all, C{getTracebackObject}
192
should just return None.
194
None is a good value, because traceback.extract_tb(None) -> [].
196
f = failure.Failure(Exception("some error"))
197
self.assertEqual(f.getTracebackObject(), None)
199
class FindFailureTests(unittest.TestCase):
201
Tests for functionality related to L{Failure._findFailure}.
204
def test_findNoFailureInExceptionHandler(self):
206
Within an exception handler, _findFailure should return
207
C{None} in case no Failure is associated with the current
213
self.assertEqual(failure.Failure._findFailure(), None)
215
self.fail("No exception raised from 1/0!?")
218
def test_findNoFailure(self):
220
Outside of an exception handler, _findFailure should return None.
222
self.assertEqual(sys.exc_info()[-1], None) #environment sanity check
223
self.assertEqual(failure.Failure._findFailure(), None)
226
def test_findFailure(self):
228
Within an exception handler, it should be possible to find the
229
original Failure that caused the current exception (if it was
230
caused by raiseException).
232
f = getDivisionFailure()
237
self.assertEqual(failure.Failure._findFailure(), f)
239
self.fail("No exception raised from raiseException!?")
242
def test_failureConstructionFindsOriginalFailure(self):
244
When a Failure is constructed in the context of an exception
245
handler that is handling an exception raised by
246
raiseException, the new Failure should be chained to that
249
f = getDivisionFailure()
254
newF = failure.Failure()
255
self.assertEqual(f.getTraceback(), newF.getTraceback())
257
self.fail("No exception raised from raiseException!?")
260
def test_failureConstructionWithMungedStackSucceeds(self):
262
Pyrex and Cython are known to insert fake stack frames so as to give
263
more Python-like tracebacks. These stack frames with empty code objects
264
should not break extraction of the exception.
267
raiser.raiseException()
268
except raiser.RaiserException:
269
f = failure.Failure()
270
self.assertTrue(f.check(raiser.RaiserException))
272
self.fail("No exception raised from extension?!")
276
skipMsg = "raiser extension not available"
277
test_failureConstructionWithMungedStackSucceeds.skip = skipMsg
281
class TestFormattableTraceback(unittest.TestCase):
283
Whitebox tests that show that L{failure._Traceback} constructs objects that
284
can be used by L{traceback.extract_tb}.
286
If the objects can be used by L{traceback.extract_tb}, then they can be
287
formatted using L{traceback.format_tb} and friends.
290
def test_singleFrame(self):
292
A C{_Traceback} object constructed with a single frame should be able
293
to be passed to L{traceback.extract_tb}, and we should get a singleton
294
list containing a (filename, lineno, methodname, line) tuple.
296
tb = failure._Traceback([['method', 'filename.py', 123, {}, {}]])
297
# Note that we don't need to test that extract_tb correctly extracts
298
# the line's contents. In this case, since filename.py doesn't exist,
299
# it will just use None.
300
self.assertEqual(traceback.extract_tb(tb),
301
[('filename.py', 123, 'method', None)])
303
def test_manyFrames(self):
305
A C{_Traceback} object constructed with multiple frames should be able
306
to be passed to L{traceback.extract_tb}, and we should get a list
307
containing a tuple for each frame.
309
tb = failure._Traceback([
310
['method1', 'filename.py', 123, {}, {}],
311
['method2', 'filename.py', 235, {}, {}]])
312
self.assertEqual(traceback.extract_tb(tb),
313
[('filename.py', 123, 'method1', None),
314
('filename.py', 235, 'method2', None)])
317
if sys.version_info[:2] >= (2, 5):
318
from twisted.test.generator_failure_tests import TwoPointFiveFailureTests