~0x44/nova/bug838466

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/test/test_failure.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
 
 
5
"""
 
6
Test cases for failure module.
 
7
"""
 
8
 
 
9
import sys
 
10
import StringIO
 
11
import traceback
 
12
 
 
13
from twisted.trial import unittest, util
 
14
 
 
15
from twisted.python import failure
 
16
 
 
17
try:
 
18
    from twisted.test import raiser
 
19
except ImportError:
 
20
    raiser = None
 
21
 
 
22
 
 
23
class BrokenStr(Exception):
 
24
    def __str__(self):
 
25
        raise self
 
26
 
 
27
 
 
28
def getDivisionFailure():
 
29
    try:
 
30
        1/0
 
31
    except:
 
32
        f = failure.Failure()
 
33
    return f
 
34
 
 
35
 
 
36
class FailureTestCase(unittest.TestCase):
 
37
 
 
38
    def testFailAndTrap(self):
 
39
        """Trapping a failure."""
 
40
        try:
 
41
            raise NotImplementedError('test')
 
42
        except:
 
43
            f = failure.Failure()
 
44
        error = f.trap(SystemExit, RuntimeError)
 
45
        self.assertEquals(error, RuntimeError)
 
46
        self.assertEquals(f.type, NotImplementedError)
 
47
 
 
48
    def test_notTrapped(self):
 
49
        """Making sure trap doesn't trap what it shouldn't."""
 
50
        try:
 
51
            raise ValueError()
 
52
        except:
 
53
            f = failure.Failure()
 
54
        self.assertRaises(failure.Failure, f.trap, OverflowError)
 
55
 
 
56
    def testPrinting(self):
 
57
        out = StringIO.StringIO()
 
58
        try:
 
59
            1/0
 
60
        except:
 
61
            f = failure.Failure()
 
62
        f.printDetailedTraceback(out)
 
63
        f.printBriefTraceback(out)
 
64
        f.printTraceback(out)
 
65
 
 
66
    def testExplictPass(self):
 
67
        e = RuntimeError()
 
68
        f = failure.Failure(e)
 
69
        f.trap(RuntimeError)
 
70
        self.assertEquals(f.value, e)
 
71
 
 
72
 
 
73
    def _getInnermostFrameLine(self, f):
 
74
        try:
 
75
            f.raiseException()
 
76
        except ZeroDivisionError:
 
77
            tb = traceback.extract_tb(sys.exc_info()[2])
 
78
            return tb[-1][-1]
 
79
        else:
 
80
            raise Exception(
 
81
                "f.raiseException() didn't raise ZeroDivisionError!?")
 
82
 
 
83
 
 
84
    def testRaiseExceptionWithTB(self):
 
85
        f = getDivisionFailure()
 
86
        innerline = self._getInnermostFrameLine(f)
 
87
        self.assertEquals(innerline, '1/0')
 
88
 
 
89
 
 
90
    def testLackOfTB(self):
 
91
        f = getDivisionFailure()
 
92
        f.cleanFailure()
 
93
        innerline = self._getInnermostFrameLine(f)
 
94
        self.assertEquals(innerline, '1/0')
 
95
 
 
96
    testLackOfTB.todo = "the traceback is not preserved, exarkun said he'll try to fix this! god knows how"
 
97
 
 
98
 
 
99
    _stringException = "bugger off"
 
100
    def _getStringFailure(self):
 
101
        try:
 
102
            raise self._stringException
 
103
        except:
 
104
            f = failure.Failure()
 
105
        return f
 
106
 
 
107
    def test_raiseStringExceptions(self):
 
108
        # String exceptions used to totally bugged f.raiseException
 
109
        f = self._getStringFailure()
 
110
        try:
 
111
            f.raiseException()
 
112
        except:
 
113
            self.assertEquals(sys.exc_info()[0], self._stringException)
 
114
        else:
 
115
            raise AssertionError("Should have raised")
 
116
    test_raiseStringExceptions.suppress = [
 
117
        util.suppress(message='raising a string exception is deprecated')]
 
118
 
 
119
 
 
120
    def test_printStringExceptions(self):
 
121
        """
 
122
        L{Failure.printTraceback} should write out stack and exception
 
123
        information, even for string exceptions.
 
124
        """
 
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)
 
131
 
 
132
    test_printStringExceptions.suppress = [
 
133
        util.suppress(message='raising a string exception is deprecated')]
 
134
 
 
135
    if sys.version_info[:2] >= (2, 6):
 
136
        skipMsg = ("String exceptions aren't supported anymore starting "
 
137
                   "Python 2.6")
 
138
        test_raiseStringExceptions.skip = skipMsg
 
139
        test_printStringExceptions.skip = skipMsg
 
140
 
 
141
 
 
142
    def testBrokenStr(self):
 
143
        """
 
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.
 
147
        """
 
148
        x = BrokenStr()
 
149
        try:
 
150
            str(x)
 
151
        except:
 
152
            f = failure.Failure()
 
153
        self.assertEquals(f.value, x)
 
154
        try:
 
155
            f.getTraceback()
 
156
        except:
 
157
            self.fail("getTraceback() shouldn't raise an exception")
 
158
 
 
159
 
 
160
    def testConstructionFails(self):
 
161
        """
 
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.
 
165
        """
 
166
        self.assertRaises(failure.NoCurrentExceptionError, failure.Failure)
 
167
 
 
168
    def test_getTracebackObject(self):
 
169
        """
 
170
        If the C{Failure} has not been cleaned, then C{getTracebackObject}
 
171
        should return the traceback object that it was given in the
 
172
        constructor.
 
173
        """
 
174
        f = getDivisionFailure()
 
175
        self.assertEqual(f.getTracebackObject(), f.tb)
 
176
 
 
177
    def test_getTracebackObjectFromClean(self):
 
178
        """
 
179
        If the Failure has been cleaned, then C{getTracebackObject} should
 
180
        return an object that looks the same to L{traceback.extract_tb}.
 
181
        """
 
182
        f = getDivisionFailure()
 
183
        expected = traceback.extract_tb(f.getTracebackObject())
 
184
        f.cleanFailure()
 
185
        observed = traceback.extract_tb(f.getTracebackObject())
 
186
        self.assertEqual(expected, observed)
 
187
 
 
188
    def test_getTracebackObjectWithoutTraceback(self):
 
189
        """
 
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.
 
193
 
 
194
        None is a good value, because traceback.extract_tb(None) -> [].
 
195
        """
 
196
        f = failure.Failure(Exception("some error"))
 
197
        self.assertEqual(f.getTracebackObject(), None)
 
198
 
 
199
class FindFailureTests(unittest.TestCase):
 
200
    """
 
201
    Tests for functionality related to L{Failure._findFailure}.
 
202
    """
 
203
 
 
204
    def test_findNoFailureInExceptionHandler(self):
 
205
        """
 
206
        Within an exception handler, _findFailure should return
 
207
        C{None} in case no Failure is associated with the current
 
208
        exception.
 
209
        """
 
210
        try:
 
211
            1/0
 
212
        except:
 
213
            self.assertEqual(failure.Failure._findFailure(), None)
 
214
        else:
 
215
            self.fail("No exception raised from 1/0!?")
 
216
 
 
217
 
 
218
    def test_findNoFailure(self):
 
219
        """
 
220
        Outside of an exception handler, _findFailure should return None.
 
221
        """
 
222
        self.assertEqual(sys.exc_info()[-1], None) #environment sanity check
 
223
        self.assertEqual(failure.Failure._findFailure(), None)
 
224
 
 
225
 
 
226
    def test_findFailure(self):
 
227
        """
 
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).
 
231
        """
 
232
        f = getDivisionFailure()
 
233
        f.cleanFailure()
 
234
        try:
 
235
            f.raiseException()
 
236
        except:
 
237
            self.assertEqual(failure.Failure._findFailure(), f)
 
238
        else:
 
239
            self.fail("No exception raised from raiseException!?")
 
240
 
 
241
 
 
242
    def test_failureConstructionFindsOriginalFailure(self):
 
243
        """
 
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
 
247
        original Failure.
 
248
        """
 
249
        f = getDivisionFailure()
 
250
        f.cleanFailure()
 
251
        try:
 
252
            f.raiseException()
 
253
        except:
 
254
            newF = failure.Failure()
 
255
            self.assertEqual(f.getTraceback(), newF.getTraceback())
 
256
        else:
 
257
            self.fail("No exception raised from raiseException!?")
 
258
 
 
259
 
 
260
    def test_failureConstructionWithMungedStackSucceeds(self):
 
261
        """
 
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.
 
265
        """
 
266
        try:
 
267
            raiser.raiseException()
 
268
        except raiser.RaiserException:
 
269
            f = failure.Failure()
 
270
            self.assertTrue(f.check(raiser.RaiserException))
 
271
        else:
 
272
            self.fail("No exception raised from extension?!")
 
273
 
 
274
 
 
275
    if raiser is None:
 
276
        skipMsg = "raiser extension not available"
 
277
        test_failureConstructionWithMungedStackSucceeds.skip = skipMsg
 
278
 
 
279
 
 
280
 
 
281
class TestFormattableTraceback(unittest.TestCase):
 
282
    """
 
283
    Whitebox tests that show that L{failure._Traceback} constructs objects that
 
284
    can be used by L{traceback.extract_tb}.
 
285
 
 
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.
 
288
    """
 
289
 
 
290
    def test_singleFrame(self):
 
291
        """
 
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.
 
295
        """
 
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)])
 
302
 
 
303
    def test_manyFrames(self):
 
304
        """
 
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.
 
308
        """
 
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)])
 
315
 
 
316
 
 
317
if sys.version_info[:2] >= (2, 5):
 
318
    from twisted.test.generator_failure_tests import TwoPointFiveFailureTests