0fc8b6b22fd1b9d999b3600a8498ba83324b9a1a
[babeltrace.git] / tests / utils / python / tap / runner.py
1 # Copyright (c) 2016, Matt Layman
2
3 import os
4 from unittest import TextTestResult, TextTestRunner
5 from unittest.runner import _WritelnDecorator
6 import sys
7
8 from tap import formatter
9 from tap.i18n import _
10 from tap.tracker import Tracker
11
12
13 class TAPTestResult(TextTestResult):
14
15 FORMAT = None
16
17 def __init__(self, stream, descriptions, verbosity):
18 super(TAPTestResult, self).__init__(stream, descriptions, verbosity)
19
20 def stopTestRun(self):
21 """Once the test run is complete, generate each of the TAP files."""
22 super(TAPTestResult, self).stopTestRun()
23 self.tracker.generate_tap_reports()
24
25 def addError(self, test, err):
26 super(TAPTestResult, self).addError(test, err)
27 diagnostics = formatter.format_exception(err)
28 self.tracker.add_not_ok(
29 self._cls_name(test), self._description(test),
30 diagnostics=diagnostics)
31
32 def addFailure(self, test, err):
33 super(TAPTestResult, self).addFailure(test, err)
34 diagnostics = formatter.format_exception(err)
35 self.tracker.add_not_ok(
36 self._cls_name(test), self._description(test),
37 diagnostics=diagnostics)
38
39 def addSuccess(self, test):
40 super(TAPTestResult, self).addSuccess(test)
41 self.tracker.add_ok(self._cls_name(test), self._description(test))
42
43 def addSkip(self, test, reason):
44 super(TAPTestResult, self).addSkip(test, reason)
45 self.tracker.add_skip(
46 self._cls_name(test), self._description(test), reason)
47
48 def addExpectedFailure(self, test, err):
49 super(TAPTestResult, self).addExpectedFailure(test, err)
50 diagnostics = formatter.format_exception(err)
51 self.tracker.add_not_ok(
52 self._cls_name(test), self._description(test),
53 _('(expected failure)'), diagnostics=diagnostics)
54
55 def addUnexpectedSuccess(self, test):
56 super(TAPTestResult, self).addUnexpectedSuccess(test)
57 self.tracker.add_ok(self._cls_name(test), self._description(test),
58 _('(unexpected success)'))
59
60 def _cls_name(self, test):
61 return test.__class__.__name__
62
63 def _description(self, test):
64 if self.FORMAT:
65 try:
66 return self.FORMAT.format(
67 method_name=str(test),
68 short_description=test.shortDescription() or '')
69 except KeyError:
70 sys.exit(_(
71 'Bad format string: {format}\n'
72 'Replacement options are: {{short_description}} and '
73 '{{method_name}}').format(format=self.FORMAT))
74
75 return test.shortDescription() or str(test)
76
77
78 # TODO: 2016-7-30 mblayman - Since the 2.6 signature is no longer relevant,
79 # check the possibility of removing the module level scope.
80
81 # Module level state stinks, but this is the only way to keep compatibility
82 # with Python 2.6. The best place for the tracker is as an instance variable
83 # on the runner, but __init__ is so different that it is not easy to create
84 # a runner that satisfies every supported Python version.
85 _tracker = Tracker()
86
87
88 class TAPTestRunner(TextTestRunner):
89 """A test runner that will behave exactly like TextTestRunner and will
90 additionally generate TAP files for each test case"""
91
92 resultclass = TAPTestResult
93
94 def set_stream(self, streaming):
95 """Set the streaming boolean option to stream TAP directly to stdout.
96
97 The test runner default output will be suppressed in favor of TAP.
98 """
99 self.stream = _WritelnDecorator(open(os.devnull, 'w'))
100 _tracker.streaming = streaming
101 _tracker.stream = sys.stdout
102
103 def _makeResult(self):
104 result = self.resultclass(
105 self.stream, self.descriptions, self.verbosity)
106 result.tracker = _tracker
107 return result
108
109 @classmethod
110 def set_outdir(cls, outdir):
111 """Set the output directory so that TAP files are written to the
112 specified outdir location.
113 """
114 # Blame the lack of unittest extensibility for this hacky method.
115 _tracker.outdir = outdir
116
117 @classmethod
118 def set_combined(cls, combined):
119 """Set the tracker to use a single output file."""
120 _tracker.combined = combined
121
122 @classmethod
123 def set_header(cls, header):
124 """Set the header display flag."""
125 _tracker.header = header
126
127 @classmethod
128 def set_format(cls, fmt):
129 """Set the format of each test line.
130
131 The format string can use:
132 * {method_name}: The test method name
133 * {short_description}: The test's docstring short description
134 """
135 TAPTestResult.FORMAT = fmt
This page took 0.031007 seconds and 4 git commands to generate.