~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/trial/test/test_reporter.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
 
# See LICENSE for details.
3
 
#
4
 
# Maintainer: Jonathan Lange <jml@twistedmatrix.com>
5
 
 
6
 
 
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
12
 
 
13
 
 
14
 
class BrokenStream(object):
15
 
    """
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.
18
 
    """
19
 
    written = False
20
 
    flushed = False
21
 
 
22
 
    def __init__(self, fObj):
23
 
        self.fObj = fObj
24
 
 
25
 
    def write(self, s):
26
 
        if self.written:
27
 
            return self.fObj.write(s)
28
 
        self.written = True
29
 
        raise IOError(errno.EINTR, "Interrupted write")
30
 
 
31
 
    def flush(self):
32
 
        if self.flushed:
33
 
            return self.fObj.flush()
34
 
        self.flushed = True
35
 
        raise IOError(errno.EINTR, "Interrupted flush")
36
 
 
37
 
 
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):
46
 
            if exp is None:
47
 
                continue
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"
52
 
                                % (exp.pattern, out))
53
 
            else:
54
 
                raise TypeError("don't know what to do with object %r"
55
 
                                % (exp,))
56
 
 
57
 
 
58
 
class TestTestResult(unittest.TestCase):
59
 
    def setUp(self):
60
 
        self.result = reporter.TestResult()
61
 
 
62
 
    def test_pyunitAddError(self):
63
 
        # pyunit passes an exc_info tuple directly to addError
64
 
        try:
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)
71
 
 
72
 
    def test_pyunitAddFailure(self):
73
 
        # pyunit passes an exc_info tuple directly to addFailure
74
 
        try:
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)
81
 
 
82
 
 
83
 
class TestReporterRealtime(TestTestResult):
84
 
    def setUp(self):
85
 
        output = StringIO.StringIO()
86
 
        self.result = reporter.Reporter(output, realtime=True)
87
 
 
88
 
 
89
 
class TestErrorReporting(StringTest):
90
 
    doubleSeparator = re.compile(r'^=+$')
91
 
 
92
 
    def setUp(self):
93
 
        self.loader = runner.TestLoader()
94
 
        self.output = StringIO.StringIO()
95
 
        self.result = reporter.Reporter(self.output)
96
 
 
97
 
    def getOutput(self, suite):
98
 
        result = self.getResult(suite)
99
 
        result.printErrors()
100
 
        return self.output.getvalue()
101
 
 
102
 
    def getResult(self, suite):
103
 
        suite.run(self.result)
104
 
        return self.result
105
 
 
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)
119
 
 
120
 
    def testFormatFailedMethod(self):
121
 
        suite = self.loader.loadMethod(erroneous.TestRegularFail.test_fail)
122
 
        output = self.getOutput(suite).splitlines()
123
 
        match = [
124
 
            self.doubleSeparator,
125
 
            '[FAIL]: '
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'
131
 
            ]
132
 
        self.stringComparison(match, output)
133
 
 
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.*'
147
 
                             + re.escape(path))]
148
 
        self.stringComparison(expect, output.splitlines())
149
 
 
150
 
    def testHiddenException(self):
151
 
        """
152
 
        Check that errors in C{DelayedCall}s get reported, even if the
153
 
        test already has a failure.
154
 
 
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.
158
 
        """
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)
166
 
 
167
 
 
168
 
class TracebackHandling(unittest.TestCase):
169
 
    def getErrorFrames(self, test):
170
 
        stream = StringIO.StringIO()
171
 
        result = reporter.Reporter(stream)
172
 
        test.run(result)
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)
177
 
 
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):],
184
 
                             expectedSegs)
185
 
        self.assertEqual(len(observedFrames), len(expectedFrames))
186
 
 
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')])
192
 
 
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')])
199
 
 
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')])
205
 
 
206
 
    def test_noFrames(self):
207
 
        result = reporter.Reporter(None)
208
 
        self.assertEqual([], result._trimFrames([]))
209
 
 
210
 
    def test_oneFrame(self):
211
 
        result = reporter.Reporter(None)
212
 
        self.assertEqual(['fake frame'], result._trimFrames(['fake frame']))
213
 
 
214
 
 
215
 
class FormatFailures(StringTest):
216
 
    def setUp(self):
217
 
        try:
218
 
            raise RuntimeError('foo')
219
 
        except RuntimeError:
220
 
            self.f = failure.Failure()
221
 
        self.f.frames = [
222
 
            ['foo', 'foo/bar.py', 5, [('x', 5)], [('y', 'orange')]],
223
 
            ['qux', 'foo/bar.py', 10, [('a', 'two')], [('b', 'MCMXCIX')]]
224
 
            ]
225
 
        self.stream = StringIO.StringIO()
226
 
        self.result = reporter.Reporter(self.stream)
227
 
 
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())
237
 
 
238
 
    def test_formatString(self):
239
 
        tb = '''
240
 
  File "twisted/trial/unittest.py", line 256, in failUnlessSubstring
241
 
    return self.failUnlessIn(substring, astring, msg)
242
 
exceptions.TypeError: iterable argument required
243
 
 
244
 
'''
245
 
        expected = '''
246
 
  File "twisted/trial/unittest.py", line 256, in failUnlessSubstring
247
 
    return self.failUnlessIn(substring, astring, msg)
248
 
exceptions.TypeError: iterable argument required
249
 
'''
250
 
        formatted = self.result._formatFailureTraceback(tb)
251
 
        self.assertEqual(expected, formatted)
252
 
 
253
 
    def test_mutation(self):
254
 
        frames = self.f.frames[:]
255
 
        tb = self.result._formatFailureTraceback(self.f)
256
 
        self.assertEqual(self.f.frames, frames)
257
 
 
258
 
 
259
 
class PyunitTestNames(unittest.TestCase):
260
 
    def setUp(self):
261
 
        from twisted.trial.test import sample
262
 
        self.stream = StringIO.StringIO()
263
 
        self.test = sample.PyunitTest('test_foo')
264
 
 
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 ... ')
271
 
 
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) + ' ...')
278
 
 
279
 
    def test_getDescription(self):
280
 
        result = reporter.TreeReporter(self.stream)
281
 
        output = result.getDescription(self.test)
282
 
        self.failUnlessEqual(output, 'test_foo')
283
 
 
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'])
290
 
 
291
 
 
292
 
class TrialTestNames(unittest.TestCase):
293
 
    def setUp(self):
294
 
        from twisted.trial.test import sample
295
 
        self.stream = StringIO.StringIO()
296
 
        self.test = sample.FooTest('test_foo')
297
 
 
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() + ' ... ')
303
 
 
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) + ' ...')
310
 
 
311
 
    def test_treeReporterWithDocstrings(self):
312
 
        """A docstring"""
313
 
        result = reporter.TreeReporter(self.stream)
314
 
        self.assertEqual(result.getDescription(self),
315
 
                         'test_treeReporterWithDocstrings')
316
 
 
317
 
    def test_getDescription(self):
318
 
        result = reporter.TreeReporter(self.stream)
319
 
        output = result.getDescription(self.test)
320
 
        self.failUnlessEqual(output, "test_foo")
321
 
 
322
 
 
323
 
class SkipTest(unittest.TestCase):
324
 
    def setUp(self):
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')
329
 
 
330
 
    def test_accumulation(self):
331
 
        self.result.addSkip(self.test, 'some reason')
332
 
        self.failUnlessEqual(1, len(self.result.skips))
333
 
 
334
 
    def test_success(self):
335
 
        self.result.addSkip(self.test, 'some reason')
336
 
        self.failUnlessEqual(True, self.result.wasSuccessful())
337
 
 
338
 
    def test_summary(self):
339
 
        self.result.addSkip(self.test, 'some reason')
340
 
        self.result.printSummary()
341
 
        output = self.stream.getvalue()
342
 
        prefix = 'PASSED '
343
 
        self.failUnless(output.startswith(prefix))
344
 
        self.failUnlessEqual(output[len(prefix):].strip(), '(skips=1)')
345
 
 
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')
351
 
 
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')
357
 
 
358
 
    def test_exceptionSkip(self):
359
 
        try:
360
 
            1/0
361
 
        except Exception, e:
362
 
            error = e
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))
367
 
 
368
 
 
369
 
 
370
 
class MockColorizer:
371
 
    """
372
 
    Used by TestTreeReporter to make sure that output is colored correctly.
373
 
    """
374
 
    def __init__(self, stream):
375
 
        self.log = []
376
 
 
377
 
    def supported(self):
378
 
        return True
379
 
    supported = classmethod(supported)
380
 
 
381
 
    def write(self, text, color):
382
 
        self.log.append((color, text))
383
 
 
384
 
 
385
 
class TestTreeReporter(unittest.TestCase):
386
 
    def setUp(self):
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
393
 
 
394
 
    def makeError(self):
395
 
        try:
396
 
            1/0
397
 
        except ZeroDivisionError:
398
 
            f = failure.Failure()
399
 
        return f
400
 
 
401
 
    def test_cleanupError(self):
402
 
        """
403
 
        Run cleanupErrors and check that the output is correct, and colored
404
 
        correctly.
405
 
        """
406
 
        f = self.makeError()
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(
415
 
        test_cleanupError,
416
 
        util.suppress(category=reporter.BrokenTestCaseWarning))
417
 
 
418
 
 
419
 
class TestReporter(unittest.TestCase):
420
 
    resultFactory = reporter.Reporter
421
 
 
422
 
    def setUp(self):
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)
427
 
        self._timer = 0
428
 
        self.result._getTime = self._getTime
429
 
 
430
 
    def _getTime(self):
431
 
        self._timer += 1
432
 
        return self._timer
433
 
 
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)
440
 
 
441
 
 
442
 
    def test_brokenStream(self):
443
 
        """
444
 
        Test that the reporter safely writes to its stream.
445
 
        """
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')
452
 
 
453
 
 
454
 
class TestSafeStream(unittest.TestCase):
455
 
    def test_safe(self):
456
 
        """
457
 
        Test that L{reporter.SafeStream} successfully write to its original
458
 
        stream even if an interrupt happens during the write.
459
 
        """
460
 
        stream = StringIO.StringIO()
461
 
        broken = BrokenStream(stream)
462
 
        safe = reporter.SafeStream(broken)
463
 
        safe.write("Hello")
464
 
        self.assertEqual(stream.getvalue(), "Hello")
465
 
 
466
 
 
467
 
class TestTimingReporter(TestReporter):
468
 
    resultFactory = reporter.TimingTextReporter