1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
# See LICENSE for details.
4
# Maintainer: Jonathan Lange <jml@twistedmatrix.com>
7
import errno, sys, os, re, StringIO
8
from twisted.internet.utils import suppressWarnings
9
from twisted.python import failure
10
from twisted.trial import unittest, runner, reporter, util
11
from twisted.trial.test import erroneous
14
class BrokenStream(object):
16
Stream-ish object that raises a signal interrupt error. We use this to make
17
sure that Trial still manages to write what it needs to write.
22
def __init__(self, fObj):
27
return self.fObj.write(s)
29
raise IOError(errno.EINTR, "Interrupted write")
33
return self.fObj.flush()
35
raise IOError(errno.EINTR, "Interrupted flush")
38
class StringTest(unittest.TestCase):
39
def stringComparison(self, expect, output):
40
output = filter(None, output)
41
self.failUnless(len(expect) <= len(output),
42
"Must have more observed than expected"
43
"lines %d < %d" % (len(output), len(expect)))
44
REGEX_PATTERN_TYPE = type(re.compile(''))
45
for exp, out in zip(expect, output):
48
elif isinstance(exp, str):
49
self.assertSubstring(exp, out)
50
elif isinstance(exp, REGEX_PATTERN_TYPE):
51
self.failUnless(exp.match(out), "%r did not match string %r"
54
raise TypeError("don't know what to do with object %r"
58
class TestTestResult(unittest.TestCase):
60
self.result = reporter.TestResult()
62
def test_pyunitAddError(self):
63
# pyunit passes an exc_info tuple directly to addError
65
raise RuntimeError('foo')
66
except RuntimeError, excValue:
67
self.result.addError(self, sys.exc_info())
68
failure = self.result.errors[0][1]
69
self.assertEqual(excValue, failure.value)
70
self.assertEqual(RuntimeError, failure.type)
72
def test_pyunitAddFailure(self):
73
# pyunit passes an exc_info tuple directly to addFailure
75
raise self.failureException('foo')
76
except self.failureException, excValue:
77
self.result.addFailure(self, sys.exc_info())
78
failure = self.result.failures[0][1]
79
self.assertEqual(excValue, failure.value)
80
self.assertEqual(self.failureException, failure.type)
83
class TestReporterRealtime(TestTestResult):
85
output = StringIO.StringIO()
86
self.result = reporter.Reporter(output, realtime=True)
89
class TestErrorReporting(StringTest):
90
doubleSeparator = re.compile(r'^=+$')
93
self.loader = runner.TestLoader()
94
self.output = StringIO.StringIO()
95
self.result = reporter.Reporter(self.output)
97
def getOutput(self, suite):
98
result = self.getResult(suite)
100
return self.output.getvalue()
102
def getResult(self, suite):
103
suite.run(self.result)
106
def testFormatErroredMethod(self):
107
suite = self.loader.loadClass(erroneous.TestFailureInSetUp)
108
output = self.getOutput(suite).splitlines()
109
match = [self.doubleSeparator,
110
('[ERROR]: twisted.trial.test.erroneous.'
111
'TestFailureInSetUp.test_noop'),
112
'Traceback (most recent call last):',
113
re.compile(r'^\s+File .*erroneous\.py., line \d+, in setUp$'),
114
re.compile(r'^\s+raise FoolishError, '
115
r'.I am a broken setUp method.$'),
116
('twisted.trial.test.erroneous.FoolishError: '
117
'I am a broken setUp method')]
118
self.stringComparison(match, output)
120
def testFormatFailedMethod(self):
121
suite = self.loader.loadMethod(erroneous.TestRegularFail.test_fail)
122
output = self.getOutput(suite).splitlines()
124
self.doubleSeparator,
126
'twisted.trial.test.erroneous.TestRegularFail.test_fail',
127
'Traceback (most recent call last):',
128
re.compile(r'^\s+File .*erroneous\.py., line \d+, in test_fail$'),
129
re.compile(r'^\s+self\.fail\("I fail"\)$'),
130
'twisted.trial.unittest.FailTest: I fail'
132
self.stringComparison(match, output)
134
def testDoctestError(self):
135
from twisted.trial.test import erroneous
136
suite = self.loader.loadDoctests(erroneous)
137
output = self.getOutput(suite)
138
path = 'twisted.trial.test.erroneous.unexpectedException'
139
for substring in ['1/0', 'ZeroDivisionError',
140
'Exception raised:', path]:
141
self.assertSubstring(substring, output)
142
self.failUnless(re.search('Fail(ed|ure in) example:', output),
143
"Couldn't match 'Failure in example: ' "
144
"or 'Failed example: '")
145
expect = [self.doubleSeparator,
146
re.compile(r'\[(ERROR|FAIL)\]: .*[Dd]octest.*'
148
self.stringComparison(expect, output.splitlines())
150
def testHiddenException(self):
152
Check that errors in C{DelayedCall}s get reported, even if the
153
test already has a failure.
155
Only really necessary for testing the deprecated style of tests that
156
use iterate() directly. See
157
L{erroneous.DelayedCall.testHiddenException} for more details.
159
test = erroneous.DelayedCall('testHiddenException')
160
result = self.getResult(test)
161
self.flushLoggedErrors(RuntimeError)
162
self.assertEqual(len(result.errors), 1)
163
self.assertEqual(len(result.failures), 1)
164
self.assertEqual(result.errors[0][1].getErrorMessage(),
165
test.hiddenExceptionMsg)
168
class TracebackHandling(unittest.TestCase):
169
def getErrorFrames(self, test):
170
stream = StringIO.StringIO()
171
result = reporter.Reporter(stream)
173
bads = result.failures + result.errors
174
assert len(bads) == 1
175
assert bads[0][0] == test
176
return result._trimFrames(bads[0][1].frames)
178
def checkFrames(self, observedFrames, expectedFrames):
179
for observed, expected in zip(observedFrames, expectedFrames):
180
self.assertEqual(observed[0], expected[0])
181
observedSegs = os.path.splitext(observed[1])[0].split(os.sep)
182
expectedSegs = expected[1].split('/')
183
self.assertEqual(observedSegs[-len(expectedSegs):],
185
self.assertEqual(len(observedFrames), len(expectedFrames))
187
def test_basic(self):
188
test = erroneous.TestRegularFail('test_fail')
189
frames = self.getErrorFrames(test)
190
self.checkFrames(frames,
191
[('test_fail', 'twisted/trial/test/erroneous')])
193
def test_subroutine(self):
194
test = erroneous.TestRegularFail('test_subfail')
195
frames = self.getErrorFrames(test)
196
self.checkFrames(frames,
197
[('test_subfail', 'twisted/trial/test/erroneous'),
198
('subroutine', 'twisted/trial/test/erroneous')])
200
def test_deferred(self):
201
test = erroneous.TestFailureInDeferredChain('test_fail')
202
frames = self.getErrorFrames(test)
203
self.checkFrames(frames,
204
[('_later', 'twisted/trial/test/erroneous')])
206
def test_noFrames(self):
207
result = reporter.Reporter(None)
208
self.assertEqual([], result._trimFrames([]))
210
def test_oneFrame(self):
211
result = reporter.Reporter(None)
212
self.assertEqual(['fake frame'], result._trimFrames(['fake frame']))
215
class FormatFailures(StringTest):
218
raise RuntimeError('foo')
220
self.f = failure.Failure()
222
['foo', 'foo/bar.py', 5, [('x', 5)], [('y', 'orange')]],
223
['qux', 'foo/bar.py', 10, [('a', 'two')], [('b', 'MCMXCIX')]]
225
self.stream = StringIO.StringIO()
226
self.result = reporter.Reporter(self.stream)
228
def test_formatDefault(self):
229
tb = self.result._formatFailureTraceback(self.f)
230
self.stringComparison([
231
'Traceback (most recent call last):',
232
' File "foo/bar.py", line 5, in foo',
233
re.compile(r'^\s*$'),
234
' File "foo/bar.py", line 10, in qux',
235
re.compile(r'^\s*$'),
236
'RuntimeError: foo'], tb.splitlines())
238
def test_formatString(self):
240
File "twisted/trial/unittest.py", line 256, in failUnlessSubstring
241
return self.failUnlessIn(substring, astring, msg)
242
exceptions.TypeError: iterable argument required
246
File "twisted/trial/unittest.py", line 256, in failUnlessSubstring
247
return self.failUnlessIn(substring, astring, msg)
248
exceptions.TypeError: iterable argument required
250
formatted = self.result._formatFailureTraceback(tb)
251
self.assertEqual(expected, formatted)
253
def test_mutation(self):
254
frames = self.f.frames[:]
255
tb = self.result._formatFailureTraceback(self.f)
256
self.assertEqual(self.f.frames, frames)
259
class PyunitTestNames(unittest.TestCase):
261
from twisted.trial.test import sample
262
self.stream = StringIO.StringIO()
263
self.test = sample.PyunitTest('test_foo')
265
def test_verboseReporter(self):
266
result = reporter.VerboseTextReporter(self.stream)
267
result.startTest(self.test)
268
output = self.stream.getvalue()
269
self.failUnlessEqual(
270
output, 'twisted.trial.test.sample.PyunitTest.test_foo ... ')
272
def test_treeReporter(self):
273
result = reporter.TreeReporter(self.stream)
274
result.startTest(self.test)
275
output = self.stream.getvalue()
276
output = output.splitlines()[-1].strip()
277
self.failUnlessEqual(output, result.getDescription(self.test) + ' ...')
279
def test_getDescription(self):
280
result = reporter.TreeReporter(self.stream)
281
output = result.getDescription(self.test)
282
self.failUnlessEqual(output, 'test_foo')
284
def test_minimalReporter(self):
285
result = reporter.MinimalReporter(self.stream)
286
self.test.run(result)
287
result.printSummary()
288
output = self.stream.getvalue().strip().split(' ')
289
self.failUnlessEqual(output[1:], ['1', '1', '0', '0', '0'])
292
class TrialTestNames(unittest.TestCase):
294
from twisted.trial.test import sample
295
self.stream = StringIO.StringIO()
296
self.test = sample.FooTest('test_foo')
298
def test_verboseReporter(self):
299
result = reporter.VerboseTextReporter(self.stream)
300
result.startTest(self.test)
301
output = self.stream.getvalue()
302
self.failUnlessEqual(output, self.test.id() + ' ... ')
304
def test_treeReporter(self):
305
result = reporter.TreeReporter(self.stream)
306
result.startTest(self.test)
307
output = self.stream.getvalue()
308
output = output.splitlines()[-1].strip()
309
self.failUnlessEqual(output, result.getDescription(self.test) + ' ...')
311
def test_treeReporterWithDocstrings(self):
313
result = reporter.TreeReporter(self.stream)
314
self.assertEqual(result.getDescription(self),
315
'test_treeReporterWithDocstrings')
317
def test_getDescription(self):
318
result = reporter.TreeReporter(self.stream)
319
output = result.getDescription(self.test)
320
self.failUnlessEqual(output, "test_foo")
323
class SkipTest(unittest.TestCase):
325
from twisted.trial.test import sample
326
self.stream = StringIO.StringIO()
327
self.result = reporter.Reporter(self.stream)
328
self.test = sample.FooTest('test_foo')
330
def test_accumulation(self):
331
self.result.addSkip(self.test, 'some reason')
332
self.failUnlessEqual(1, len(self.result.skips))
334
def test_success(self):
335
self.result.addSkip(self.test, 'some reason')
336
self.failUnlessEqual(True, self.result.wasSuccessful())
338
def test_summary(self):
339
self.result.addSkip(self.test, 'some reason')
340
self.result.printSummary()
341
output = self.stream.getvalue()
343
self.failUnless(output.startswith(prefix))
344
self.failUnlessEqual(output[len(prefix):].strip(), '(skips=1)')
346
def test_basicErrors(self):
347
self.result.addSkip(self.test, 'some reason')
348
self.result.printErrors()
349
output = self.stream.getvalue().splitlines()[-1]
350
self.failUnlessEqual(output.strip(), 'some reason')
352
def test_booleanSkip(self):
353
self.result.addSkip(self.test, True)
354
self.result.printErrors()
355
output = self.stream.getvalue().splitlines()[-1]
356
self.failUnlessEqual(output.strip(), 'True')
358
def test_exceptionSkip(self):
363
self.result.addSkip(self.test, error)
364
self.result.printErrors()
365
output = '\n'.join(self.stream.getvalue().splitlines()[3:]).strip()
366
self.failUnlessEqual(output, str(e))
372
Used by TestTreeReporter to make sure that output is colored correctly.
374
def __init__(self, stream):
379
supported = classmethod(supported)
381
def write(self, text, color):
382
self.log.append((color, text))
385
class TestTreeReporter(unittest.TestCase):
387
from twisted.trial.test import sample
388
self.test = sample.FooTest('test_foo')
389
self.stream = StringIO.StringIO()
390
self.result = reporter.TreeReporter(self.stream)
391
self.result._colorizer = MockColorizer(self.stream)
392
self.log = self.result._colorizer.log
397
except ZeroDivisionError:
398
f = failure.Failure()
401
def test_cleanupError(self):
403
Run cleanupErrors and check that the output is correct, and colored
407
self.result.cleanupErrors(f)
408
color, text = self.log[0]
409
self.assertEqual(color.strip(), self.result.ERROR)
410
self.assertEqual(text.strip(), 'cleanup errors')
411
color, text = self.log[1]
412
self.assertEqual(color.strip(), self.result.ERROR)
413
self.assertEqual(text.strip(), '[ERROR]')
414
test_cleanupError = suppressWarnings(
416
util.suppress(category=reporter.BrokenTestCaseWarning))
419
class TestReporter(unittest.TestCase):
420
resultFactory = reporter.Reporter
423
from twisted.trial.test import sample
424
self.test = sample.FooTest('test_foo')
425
self.stream = StringIO.StringIO()
426
self.result = self.resultFactory(self.stream)
428
self.result._getTime = self._getTime
434
def test_startStop(self):
435
self.result.startTest(self.test)
436
self.result.stopTest(self.test)
437
self.assertTrue(self.result._lastTime > 0)
438
self.assertEqual(self.result.testsRun, 1)
439
self.assertEqual(self.result.wasSuccessful(), True)
442
def test_brokenStream(self):
444
Test that the reporter safely writes to its stream.
446
result = self.resultFactory(stream=BrokenStream(self.stream))
447
result.writeln("Hello")
448
self.assertEqual(self.stream.getvalue(), 'Hello\n')
449
self.stream.truncate(0)
450
result.writeln("Hello %s!", 'World')
451
self.assertEqual(self.stream.getvalue(), 'Hello World!\n')
454
class TestSafeStream(unittest.TestCase):
457
Test that L{reporter.SafeStream} successfully write to its original
458
stream even if an interrupt happens during the write.
460
stream = StringIO.StringIO()
461
broken = BrokenStream(stream)
462
safe = reporter.SafeStream(broken)
464
self.assertEqual(stream.getvalue(), "Hello")
467
class TestTimingReporter(TestReporter):
468
resultFactory = reporter.TimingTextReporter