1"""Monkey patch lame-o vanilla unittest with test skip feature.
2
3From the patch that was never applied (shameful!):
4http://bugs.python.org/issue1034053
5"""
6
7import time, unittest
8
9
10class SkipException(Exception):
11    pass
12
13
14def TestResult__init__(self):
15    self.failures = []
16    self.errors = []
17    self.skipped = []
18    self.testsRun = 0
19    self.shouldStop = 0
20
21unittest.TestResult.__init__ = TestResult__init__
22
23
24def TestResult_addSkipped(self, test, err):
25    """Called when a test is skipped.
26
27    'err' is a tuple of values as returned by sys.exc_info().
28    """
29    self.skipped.append((test, str(err[1])))
30
31unittest.TestResult.addSkipped = TestResult_addSkipped
32
33
34def TestResult__repr__(self):
35    return "<%s run=%i errors=%i failures=%i skipped=%i>" % (
36        unittest._strclass(self.__class__), self.testsRun,
37        len(self.errors), len(self.failures), len(self.skipped))
38
39unittest.TestResult.__repr__ = TestResult__repr__
40
41
42class TestCase(unittest.TestCase):
43    # Yuck, all of run has to be copied for this.
44    # I don't care about wrapping setUp atm.
45    def run(self, result=None):
46        if result is None: result = self.defaultTestResult()
47        result.startTest(self)
48        # Support variable naming differences between 2.4 and 2.6
49        # Yay for silly variable hiding
50        try:
51            testMethodName = self.__testMethodName
52            exc_info = self.__exc_info
53        except AttributeError:
54            testMethodName = self._testMethodName
55            exc_info = self._exc_info
56
57        testMethod = getattr(self, testMethodName)
58
59        try:
60            try:
61                self.setUp()
62            except KeyboardInterrupt:
63                raise
64            except:
65                result.addError(self, exc_info())
66                return
67
68            ok = False
69            try:
70                testMethod()
71                ok = True
72            except self.failureException:
73                result.addFailure(self, exc_info())
74            except SkipException:
75                result.addSkipped(self, exc_info())
76            except KeyboardInterrupt:
77                raise
78            except:
79                result.addError(self, exc_info())
80
81            try:
82                self.tearDown()
83            except KeyboardInterrupt:
84                raise
85            except:
86                result.addError(self, exc_info())
87                ok = False
88            if ok: result.addSuccess(self)
89        finally:
90            result.stopTest(self)
91
92
93    def skip(self, msg=None):
94        """Skip the test, with the given message."""
95        raise SkipException(msg)
96
97
98    def skipIf(self, expr, msg=None):
99        """Skip the test if the expression is true."""
100        if expr:
101            raise SkipException(msg)
102
103
104def _TextTestResult_addSkipped(self, test, err):
105    unittest.TestResult.addSkipped(self, test, err)
106    if self.showAll:
107        msg = str(err[1])
108        if msg:
109            msg = " (" + msg + ")"
110        self.stream.writeln("SKIPPED" + msg)
111    elif self.dots:
112        self.stream.write('S')
113
114unittest._TextTestResult.addSkipped = _TextTestResult_addSkipped
115
116
117# Bah
118def TextTestRunner_run(self, test):
119    "Run the given test case or test suite."
120    result = self._makeResult()
121    startTime = time.time()
122    test(result)
123    stopTime = time.time()
124    timeTaken = stopTime - startTime
125    result.printErrors()
126    self.stream.writeln(result.separator2)
127    run = result.testsRun
128    self.stream.writeln("Ran %d test%s in %.3fs" %
129                        (run, run != 1 and "s" or "", timeTaken))
130    self.stream.writeln()
131    if not result.wasSuccessful():
132        self.stream.write("FAILED (")
133        failed, errored, skipped = map(
134            len, (result.failures, result.errors, result.skipped))
135        if failed:
136            self.stream.write("failures=%d" % failed)
137        if errored:
138            if failed: self.stream.write(", ")
139            self.stream.write("errors=%d" % errored)
140        if skipped:
141            self.stream.write(", skipped=%d" % skipped)
142        self.stream.writeln(")")
143    else:
144        if result.skipped:
145            self.stream.writeln(
146                "OK (skipped=%d)" % len(result.skipped))
147        else:
148            self.stream.writeln("OK")
149    return result
150
151unittest.TextTestRunner.run = TextTestRunner_run
152