blob: 2fe01f67271040c5b107748d63aa81f89188a36a [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Running tests"""
2
3import sys
4import time
5
6from . import result
7
8
9class _WritelnDecorator(object):
10 """Used to decorate file-like objects with a handy 'writeln' method"""
11 def __init__(self,stream):
12 self.stream = stream
13
14 def __getattr__(self, attr):
Antoine Pitrou47dded62009-11-10 21:39:25 +000015 if attr in ('stream', '__getstate__'):
Antoine Pitrou0734c632009-11-10 20:49:30 +000016 raise AttributeError(attr)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000017 return getattr(self.stream,attr)
18
19 def writeln(self, arg=None):
20 if arg:
21 self.write(arg)
22 self.write('\n') # text-mode streams translate to \r\n if needed
23
24
Michael Foorddb43b5a2010-02-10 14:25:12 +000025class TextTestResult(result.TestResult):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000026 """A test result class that can print formatted text results to a stream.
27
28 Used by TextTestRunner.
29 """
30 separator1 = '=' * 70
31 separator2 = '-' * 70
32
33 def __init__(self, stream, descriptions, verbosity):
Michael Foorddb43b5a2010-02-10 14:25:12 +000034 super(TextTestResult, self).__init__()
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000035 self.stream = stream
36 self.showAll = verbosity > 1
37 self.dots = verbosity == 1
38 self.descriptions = descriptions
39
40 def getDescription(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000041 doc_first_line = test.shortDescription()
42 if self.descriptions and doc_first_line:
43 return '\n'.join((str(test), doc_first_line))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000044 else:
45 return str(test)
46
47 def startTest(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000048 super(TextTestResult, self).startTest(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000049 if self.showAll:
50 self.stream.write(self.getDescription(test))
51 self.stream.write(" ... ")
52 self.stream.flush()
53
54 def addSuccess(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000055 super(TextTestResult, self).addSuccess(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000056 if self.showAll:
57 self.stream.writeln("ok")
58 elif self.dots:
59 self.stream.write('.')
60 self.stream.flush()
61
62 def addError(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000063 super(TextTestResult, self).addError(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000064 if self.showAll:
65 self.stream.writeln("ERROR")
66 elif self.dots:
67 self.stream.write('E')
68 self.stream.flush()
69
70 def addFailure(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000071 super(TextTestResult, self).addFailure(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000072 if self.showAll:
73 self.stream.writeln("FAIL")
74 elif self.dots:
75 self.stream.write('F')
76 self.stream.flush()
77
78 def addSkip(self, test, reason):
Michael Foorddb43b5a2010-02-10 14:25:12 +000079 super(TextTestResult, self).addSkip(test, reason)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000080 if self.showAll:
81 self.stream.writeln("skipped {0!r}".format(reason))
82 elif self.dots:
83 self.stream.write("s")
84 self.stream.flush()
85
86 def addExpectedFailure(self, test, err):
Michael Foorddb43b5a2010-02-10 14:25:12 +000087 super(TextTestResult, self).addExpectedFailure(test, err)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000088 if self.showAll:
89 self.stream.writeln("expected failure")
90 elif self.dots:
91 self.stream.write("x")
92 self.stream.flush()
93
94 def addUnexpectedSuccess(self, test):
Michael Foorddb43b5a2010-02-10 14:25:12 +000095 super(TextTestResult, self).addUnexpectedSuccess(test)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000096 if self.showAll:
97 self.stream.writeln("unexpected success")
98 elif self.dots:
99 self.stream.write("u")
100 self.stream.flush()
101
102 def printErrors(self):
103 if self.dots or self.showAll:
104 self.stream.writeln()
105 self.printErrorList('ERROR', self.errors)
106 self.printErrorList('FAIL', self.failures)
107
108 def printErrorList(self, flavour, errors):
109 for test, err in errors:
110 self.stream.writeln(self.separator1)
111 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
112 self.stream.writeln(self.separator2)
113 self.stream.writeln("%s" % err)
114
115
116class TextTestRunner(object):
117 """A test runner class that displays results in textual form.
118
119 It prints out the names of tests as they are run, errors as they
120 occur, and a summary of the results at the end of the test run.
121 """
Michael Foorddb43b5a2010-02-10 14:25:12 +0000122 resultclass = TextTestResult
123
124 def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
125 resultclass=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000126 self.stream = _WritelnDecorator(stream)
127 self.descriptions = descriptions
128 self.verbosity = verbosity
Michael Foorddb43b5a2010-02-10 14:25:12 +0000129 if resultclass is not None:
130 self.resultclass = resultclass
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000131
132 def _makeResult(self):
Michael Foorddb43b5a2010-02-10 14:25:12 +0000133 return self.resultclass(self.stream, self.descriptions, self.verbosity)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000134
135 def run(self, test):
136 "Run the given test case or test suite."
137 result = self._makeResult()
138 startTime = time.time()
139 startTestRun = getattr(result, 'startTestRun', None)
140 if startTestRun is not None:
141 startTestRun()
142 try:
143 test(result)
144 finally:
145 stopTestRun = getattr(result, 'stopTestRun', None)
146 if stopTestRun is not None:
147 stopTestRun()
148 stopTime = time.time()
149 timeTaken = stopTime - startTime
150 result.printErrors()
Michael Foordd99ef9a2010-02-23 17:00:53 +0000151 if hasattr(result, 'separator2'):
152 self.stream.writeln(result.separator2)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000153 run = result.testsRun
154 self.stream.writeln("Ran %d test%s in %.3fs" %
155 (run, run != 1 and "s" or "", timeTaken))
156 self.stream.writeln()
Michael Foordd99ef9a2010-02-23 17:00:53 +0000157
158 expectedFails = unexpectedSuccesses = skipped = 0
159 try:
160 results = map(len, (result.expectedFailures,
161 result.unexpectedSuccesses,
162 result.skipped))
163 expectedFails, unexpectedSuccesses, skipped = results
164 except AttributeError:
165 pass
166
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000167 infos = []
168 if not result.wasSuccessful():
169 self.stream.write("FAILED")
170 failed, errored = map(len, (result.failures, result.errors))
171 if failed:
172 infos.append("failures=%d" % failed)
173 if errored:
174 infos.append("errors=%d" % errored)
175 else:
176 self.stream.write("OK")
177 if skipped:
178 infos.append("skipped=%d" % skipped)
179 if expectedFails:
180 infos.append("expected failures=%d" % expectedFails)
181 if unexpectedSuccesses:
182 infos.append("unexpected successes=%d" % unexpectedSuccesses)
183 if infos:
184 self.stream.writeln(" (%s)" % (", ".join(infos),))
185 else:
186 self.stream.write("\n")
187 return result