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