1"""Running tests"""
2
3import sys
4import time
5import unittest
6import progress
7
8from unittest2 import result
9
10try:
11    from unittest2.signals import registerResult
12except ImportError:
13    def registerResult(_):
14        pass
15
16__unittest = True
17
18
19class _WritelnDecorator(object):
20    """Used to decorate file-like objects with a handy 'writeln' method"""
21
22    def __init__(self, stream):
23        self.stream = stream
24
25    def __getattr__(self, attr):
26        if attr in ('stream', '__getstate__'):
27            raise AttributeError(attr)
28        return getattr(self.stream, attr)
29
30    def writeln(self, arg=None):
31        if arg:
32            self.write(arg)
33        self.write('\n')  # text-mode streams translate to \r\n if needed
34
35
36class TextTestResult(result.TestResult):
37    """A test result class that can print formatted text results to a stream.
38
39    Used by TextTestRunner.
40    """
41    separator1 = '=' * 70
42    separator2 = '-' * 70
43
44    def __init__(self, stream, descriptions, verbosity):
45        super(TextTestResult, self).__init__()
46        self.stream = stream
47        self.showAll = verbosity > 1
48        self.dots = verbosity == 1
49        self.descriptions = descriptions
50        self.progressbar = None
51
52        if self.dots:
53            self.stream.writeln(
54                ".=success F=fail E=error s=skipped x=expected-fail u=unexpected-success")
55            self.stream.writeln("")
56            self.stream.flush()
57
58    def getDescription(self, test):
59        doc_first_line = test.shortDescription()
60        if self.descriptions and doc_first_line:
61            return '\n'.join((str(test), doc_first_line))
62        else:
63            return str(test)
64
65    def startTest(self, test):
66        super(TextTestResult, self).startTest(test)
67        if self.showAll:
68            self.stream.write(self.getDescription(test))
69            self.stream.write(" ... ")
70            self.stream.flush()
71
72    def newTestResult(self, test, result_short, result_long):
73        if self.showAll:
74            self.stream.writeln(result_long)
75        elif self.progressbar:
76            self.progressbar.__add__(1)
77            self.progressbar.add_event(result_short)
78            self.progressbar.show_progress()
79        elif self.dots:
80            self.stream.write(result_short)
81            self.stream.flush()
82
83    def addSuccess(self, test):
84        super(TextTestResult, self).addSuccess(test)
85        if self.progressbar:
86            self.newTestResult(test, "ok", "ok")
87        else:
88            self.newTestResult(test, ".", "ok")
89
90    def addError(self, test, err):
91        super(TextTestResult, self).addError(test, err)
92        self.newTestResult(test, "E", "ERROR")
93
94    def addFailure(self, test, err):
95        super(TextTestResult, self).addFailure(test, err)
96        self.newTestResult(test, "F", "FAILURE")
97
98    def addSkip(self, test, reason):
99        super(TextTestResult, self).addSkip(test, reason)
100        self.newTestResult(test, "s", "skipped %r" % (reason,))
101
102    def addExpectedFailure(self, test, err, bugnumber):
103        super(TextTestResult, self).addExpectedFailure(test, err, bugnumber)
104        self.newTestResult(test, "x", "expected failure")
105
106    def addUnexpectedSuccess(self, test, bugnumber):
107        super(TextTestResult, self).addUnexpectedSuccess(test, bugnumber)
108        self.newTestResult(test, "u", "unexpected success")
109
110    def printErrors(self):
111        if self.progressbar:
112            self.progressbar.complete()
113            self.progressbar.show_progress()
114        if self.dots or self.showAll:
115            self.stream.writeln()
116        self.printErrorList('ERROR', self.errors)
117        self.printErrorList('FAIL', self.failures)
118
119    def printErrorList(self, flavour, errors):
120        for test, err in errors:
121            self.stream.writeln(self.separator1)
122            self.stream.writeln("%s: %s" %
123                                (flavour, self.getDescription(test)))
124            self.stream.writeln(self.separator2)
125            self.stream.writeln("%s" % err)
126
127    def stopTestRun(self):
128        super(TextTestResult, self).stopTestRun()
129        self.printErrors()
130
131
132class TextTestRunner(unittest.TextTestRunner):
133    """A test runner class that displays results in textual form.
134
135    It prints out the names of tests as they are run, errors as they
136    occur, and a summary of the results at the end of the test run.
137    """
138    resultclass = TextTestResult
139
140    def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
141                 failfast=False, buffer=False, resultclass=None):
142        self.stream = _WritelnDecorator(stream)
143        self.descriptions = descriptions
144        self.verbosity = verbosity
145        self.failfast = failfast
146        self.buffer = buffer
147        if resultclass is not None:
148            self.resultclass = resultclass
149
150    def _makeResult(self):
151        return self.resultclass(self.stream, self.descriptions, self.verbosity)
152
153    def run(self, test):
154        "Run the given test case or test suite."
155        result = self._makeResult()
156        result.failfast = self.failfast
157        result.buffer = self.buffer
158        registerResult(result)
159
160        startTime = time.time()
161        startTestRun = getattr(result, 'startTestRun', None)
162        if startTestRun is not None:
163            startTestRun()
164        try:
165            test(result)
166        finally:
167            stopTestRun = getattr(result, 'stopTestRun', None)
168            if stopTestRun is not None:
169                stopTestRun()
170            else:
171                result.printErrors()
172        stopTime = time.time()
173        timeTaken = stopTime - startTime
174        if hasattr(result, 'separator2'):
175            self.stream.writeln(result.separator2)
176        run = result.testsRun
177        self.stream.writeln("Ran %d test%s in %.3fs" %
178                            (run, run != 1 and "s" or "", timeTaken))
179        self.stream.writeln()
180
181        expectedFails = unexpectedSuccesses = skipped = passed = failed = errored = 0
182        try:
183            results = map(len, (result.expectedFailures,
184                                result.unexpectedSuccesses,
185                                result.skipped,
186                                result.passes,
187                                result.failures,
188                                result.errors))
189            expectedFails, unexpectedSuccesses, skipped, passed, failed, errored = results
190        except AttributeError:
191            pass
192        infos = []
193        infos.append("%d passes" % passed)
194        infos.append("%d failures" % failed)
195        infos.append("%d errors" % errored)
196        infos.append("%d skipped" % skipped)
197        infos.append("%d expected failures" % expectedFails)
198        infos.append("%d unexpected successes" % unexpectedSuccesses)
199        self.stream.write("RESULT: ")
200        if not result.wasSuccessful():
201            self.stream.write("FAILED")
202        else:
203            self.stream.write("PASSED")
204
205        self.stream.writeln(" (%s)" % (", ".join(infos),))
206        return result
207