-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathplugin.py
114 lines (94 loc) · 3.87 KB
/
plugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# Copyright (c) 2020, Matt Layman
import os
import sys
from unittest import SkipTest
from nose.plugins import Plugin
from nose.suite import ContextSuite
from tap import formatter
from tap.tracker import Tracker
from nose_tap.i18n import _
class DummyStream(object):
def write(self, *args):
pass
def writeln(self, *args):
pass
def flush(self):
pass
class TAP(Plugin):
"""This plugin provides test results in the Test Anything Protocol format.
"""
name = 'tap'
def options(self, parser, env=os.environ):
super(TAP, self).options(parser, env=env)
parser.add_option(
'--tap-stream', default=False, action='store_true',
help=_('Stream TAP output instead of the default test runner'
' output.'))
parser.add_option(
'--tap-outdir', metavar='PATH', help=_(
'An optional output directory to write TAP files to. '
'If the directory does not exist, it will be created.'))
parser.add_option(
'--tap-combined', default=False, action='store_true',
help=_('Store all TAP test results into a combined output file.'))
parser.add_option(
'--tap-format', default='', metavar='FORMAT',
help=_(
'An optional format string for the TAP output.'
' The format options are:'
' {short_description} for the short description, and'
' {method_name} for the test method name.'))
def configure(self, options, conf):
super(TAP, self).configure(options, conf)
if self.enabled:
self.tracker = Tracker(
outdir=options.tap_outdir, combined=options.tap_combined,
streaming=options.tap_stream)
self._format = options.tap_format
def finalize(self, results):
self.tracker.generate_tap_reports()
def setOutputStream(self, stream):
# When streaming is on, hijack the stream and return a dummy to send
# standard nose output to oblivion.
if self.tracker.streaming:
self.tracker.stream = stream
return DummyStream()
return stream
def addError(self, test, err):
err_cls, reason, _ = err
if err_cls != SkipTest:
diagnostics = formatter.format_exception(err)
self.tracker.add_not_ok(
self._cls_name(test), self._description(test),
diagnostics=diagnostics)
else:
self.tracker.add_skip(
self._cls_name(test), self._description(test), reason)
def addFailure(self, test, err):
diagnostics = formatter.format_exception(err)
self.tracker.add_not_ok(
self._cls_name(test), self._description(test),
diagnostics=diagnostics)
def addSuccess(self, test):
self.tracker.add_ok(self._cls_name(test), self._description(test))
def _cls_name(self, test):
if isinstance(test, ContextSuite):
# In the class setup and teardown, test is a ContextSuite
# instead of a test case. Grab the name from the context.
return test.context.__name__
else:
# nose masks the true test case name so the real class name
# is found under the test attribute.
return test.test.__class__.__name__
def _description(self, test):
if self._format:
try:
return self._format.format(
method_name=str(test),
short_description=test.shortDescription() or '')
except KeyError:
sys.exit(_(
'Bad format string: {format}\n'
'Replacement options are: {{short_description}} and '
'{{method_name}}').format(format=self._format))
return test.shortDescription() or str(test)