1import io
2import os
3import sys
4import pickle
5import subprocess
6
7import unittest
8from unittest.case import _Outcome
9
10from unittest.test.support import (LoggingResult,
11                                   ResultWithNoStartTestRunStopTestRun)
12
13
14class TestCleanUp(unittest.TestCase):
15
16    def testCleanUp(self):
17        class TestableTest(unittest.TestCase):
18            def testNothing(self):
19                pass
20
21        test = TestableTest('testNothing')
22        self.assertEqual(test._cleanups, [])
23
24        cleanups = []
25
26        def cleanup1(*args, **kwargs):
27            cleanups.append((1, args, kwargs))
28
29        def cleanup2(*args, **kwargs):
30            cleanups.append((2, args, kwargs))
31
32        test.addCleanup(cleanup1, 1, 2, 3, four='hello', five='goodbye')
33        test.addCleanup(cleanup2)
34
35        self.assertEqual(test._cleanups,
36                         [(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')),
37                          (cleanup2, (), {})])
38
39        self.assertTrue(test.doCleanups())
40        self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
41
42    def testCleanUpWithErrors(self):
43        class TestableTest(unittest.TestCase):
44            def testNothing(self):
45                pass
46
47        test = TestableTest('testNothing')
48        outcome = test._outcome = _Outcome()
49
50        exc1 = Exception('foo')
51        exc2 = Exception('bar')
52        def cleanup1():
53            raise exc1
54
55        def cleanup2():
56            raise exc2
57
58        test.addCleanup(cleanup1)
59        test.addCleanup(cleanup2)
60
61        self.assertFalse(test.doCleanups())
62        self.assertFalse(outcome.success)
63
64        ((_, (Type1, instance1, _)),
65         (_, (Type2, instance2, _))) = reversed(outcome.errors)
66        self.assertEqual((Type1, instance1), (Exception, exc1))
67        self.assertEqual((Type2, instance2), (Exception, exc2))
68
69    def testCleanupInRun(self):
70        blowUp = False
71        ordering = []
72
73        class TestableTest(unittest.TestCase):
74            def setUp(self):
75                ordering.append('setUp')
76                if blowUp:
77                    raise Exception('foo')
78
79            def testNothing(self):
80                ordering.append('test')
81
82            def tearDown(self):
83                ordering.append('tearDown')
84
85        test = TestableTest('testNothing')
86
87        def cleanup1():
88            ordering.append('cleanup1')
89        def cleanup2():
90            ordering.append('cleanup2')
91        test.addCleanup(cleanup1)
92        test.addCleanup(cleanup2)
93
94        def success(some_test):
95            self.assertEqual(some_test, test)
96            ordering.append('success')
97
98        result = unittest.TestResult()
99        result.addSuccess = success
100
101        test.run(result)
102        self.assertEqual(ordering, ['setUp', 'test', 'tearDown',
103                                    'cleanup2', 'cleanup1', 'success'])
104
105        blowUp = True
106        ordering = []
107        test = TestableTest('testNothing')
108        test.addCleanup(cleanup1)
109        test.run(result)
110        self.assertEqual(ordering, ['setUp', 'cleanup1'])
111
112    def testTestCaseDebugExecutesCleanups(self):
113        ordering = []
114
115        class TestableTest(unittest.TestCase):
116            def setUp(self):
117                ordering.append('setUp')
118                self.addCleanup(cleanup1)
119
120            def testNothing(self):
121                ordering.append('test')
122
123            def tearDown(self):
124                ordering.append('tearDown')
125
126        test = TestableTest('testNothing')
127
128        def cleanup1():
129            ordering.append('cleanup1')
130            test.addCleanup(cleanup2)
131        def cleanup2():
132            ordering.append('cleanup2')
133
134        test.debug()
135        self.assertEqual(ordering, ['setUp', 'test', 'tearDown', 'cleanup1', 'cleanup2'])
136
137
138class Test_TextTestRunner(unittest.TestCase):
139    """Tests for TextTestRunner."""
140
141    def setUp(self):
142        # clean the environment from pre-existing PYTHONWARNINGS to make
143        # test_warnings results consistent
144        self.pythonwarnings = os.environ.get('PYTHONWARNINGS')
145        if self.pythonwarnings:
146            del os.environ['PYTHONWARNINGS']
147
148    def tearDown(self):
149        # bring back pre-existing PYTHONWARNINGS if present
150        if self.pythonwarnings:
151            os.environ['PYTHONWARNINGS'] = self.pythonwarnings
152
153    def test_init(self):
154        runner = unittest.TextTestRunner()
155        self.assertFalse(runner.failfast)
156        self.assertFalse(runner.buffer)
157        self.assertEqual(runner.verbosity, 1)
158        self.assertEqual(runner.warnings, None)
159        self.assertTrue(runner.descriptions)
160        self.assertEqual(runner.resultclass, unittest.TextTestResult)
161        self.assertFalse(runner.tb_locals)
162
163    def test_multiple_inheritance(self):
164        class AResult(unittest.TestResult):
165            def __init__(self, stream, descriptions, verbosity):
166                super(AResult, self).__init__(stream, descriptions, verbosity)
167
168        class ATextResult(unittest.TextTestResult, AResult):
169            pass
170
171        # This used to raise an exception due to TextTestResult not passing
172        # on arguments in its __init__ super call
173        ATextResult(None, None, 1)
174
175    def testBufferAndFailfast(self):
176        class Test(unittest.TestCase):
177            def testFoo(self):
178                pass
179        result = unittest.TestResult()
180        runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True,
181                                         buffer=True)
182        # Use our result object
183        runner._makeResult = lambda: result
184        runner.run(Test('testFoo'))
185
186        self.assertTrue(result.failfast)
187        self.assertTrue(result.buffer)
188
189    def test_locals(self):
190        runner = unittest.TextTestRunner(stream=io.StringIO(), tb_locals=True)
191        result = runner.run(unittest.TestSuite())
192        self.assertEqual(True, result.tb_locals)
193
194    def testRunnerRegistersResult(self):
195        class Test(unittest.TestCase):
196            def testFoo(self):
197                pass
198        originalRegisterResult = unittest.runner.registerResult
199        def cleanup():
200            unittest.runner.registerResult = originalRegisterResult
201        self.addCleanup(cleanup)
202
203        result = unittest.TestResult()
204        runner = unittest.TextTestRunner(stream=io.StringIO())
205        # Use our result object
206        runner._makeResult = lambda: result
207
208        self.wasRegistered = 0
209        def fakeRegisterResult(thisResult):
210            self.wasRegistered += 1
211            self.assertEqual(thisResult, result)
212        unittest.runner.registerResult = fakeRegisterResult
213
214        runner.run(unittest.TestSuite())
215        self.assertEqual(self.wasRegistered, 1)
216
217    def test_works_with_result_without_startTestRun_stopTestRun(self):
218        class OldTextResult(ResultWithNoStartTestRunStopTestRun):
219            separator2 = ''
220            def printErrors(self):
221                pass
222
223        class Runner(unittest.TextTestRunner):
224            def __init__(self):
225                super(Runner, self).__init__(io.StringIO())
226
227            def _makeResult(self):
228                return OldTextResult()
229
230        runner = Runner()
231        runner.run(unittest.TestSuite())
232
233    def test_startTestRun_stopTestRun_called(self):
234        class LoggingTextResult(LoggingResult):
235            separator2 = ''
236            def printErrors(self):
237                pass
238
239        class LoggingRunner(unittest.TextTestRunner):
240            def __init__(self, events):
241                super(LoggingRunner, self).__init__(io.StringIO())
242                self._events = events
243
244            def _makeResult(self):
245                return LoggingTextResult(self._events)
246
247        events = []
248        runner = LoggingRunner(events)
249        runner.run(unittest.TestSuite())
250        expected = ['startTestRun', 'stopTestRun']
251        self.assertEqual(events, expected)
252
253    def test_pickle_unpickle(self):
254        # Issue #7197: a TextTestRunner should be (un)pickleable. This is
255        # required by test_multiprocessing under Windows (in verbose mode).
256        stream = io.StringIO("foo")
257        runner = unittest.TextTestRunner(stream)
258        for protocol in range(2, pickle.HIGHEST_PROTOCOL + 1):
259            s = pickle.dumps(runner, protocol)
260            obj = pickle.loads(s)
261            # StringIO objects never compare equal, a cheap test instead.
262            self.assertEqual(obj.stream.getvalue(), stream.getvalue())
263
264    def test_resultclass(self):
265        def MockResultClass(*args):
266            return args
267        STREAM = object()
268        DESCRIPTIONS = object()
269        VERBOSITY = object()
270        runner = unittest.TextTestRunner(STREAM, DESCRIPTIONS, VERBOSITY,
271                                         resultclass=MockResultClass)
272        self.assertEqual(runner.resultclass, MockResultClass)
273
274        expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
275        self.assertEqual(runner._makeResult(), expectedresult)
276
277    def test_warnings(self):
278        """
279        Check that warnings argument of TextTestRunner correctly affects the
280        behavior of the warnings.
281        """
282        # see #10535 and the _test_warnings file for more information
283
284        def get_parse_out_err(p):
285            return [b.splitlines() for b in p.communicate()]
286        opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE,
287                    cwd=os.path.dirname(__file__))
288        ae_msg = b'Please use assertEqual instead.'
289        at_msg = b'Please use assertTrue instead.'
290
291        # no args -> all the warnings are printed, unittest warnings only once
292        p = subprocess.Popen([sys.executable, '_test_warnings.py'], **opts)
293        with p:
294            out, err = get_parse_out_err(p)
295        self.assertIn(b'OK', err)
296        # check that the total number of warnings in the output is correct
297        self.assertEqual(len(out), 12)
298        # check that the numbers of the different kind of warnings is correct
299        for msg in [b'dw', b'iw', b'uw']:
300            self.assertEqual(out.count(msg), 3)
301        for msg in [ae_msg, at_msg, b'rw']:
302            self.assertEqual(out.count(msg), 1)
303
304        args_list = (
305            # passing 'ignore' as warnings arg -> no warnings
306            [sys.executable, '_test_warnings.py', 'ignore'],
307            # -W doesn't affect the result if the arg is passed
308            [sys.executable, '-Wa', '_test_warnings.py', 'ignore'],
309            # -W affects the result if the arg is not passed
310            [sys.executable, '-Wi', '_test_warnings.py']
311        )
312        # in all these cases no warnings are printed
313        for args in args_list:
314            p = subprocess.Popen(args, **opts)
315            with p:
316                out, err = get_parse_out_err(p)
317            self.assertIn(b'OK', err)
318            self.assertEqual(len(out), 0)
319
320
321        # passing 'always' as warnings arg -> all the warnings printed,
322        #                                     unittest warnings only once
323        p = subprocess.Popen([sys.executable, '_test_warnings.py', 'always'],
324                             **opts)
325        with p:
326            out, err = get_parse_out_err(p)
327        self.assertIn(b'OK', err)
328        self.assertEqual(len(out), 14)
329        for msg in [b'dw', b'iw', b'uw', b'rw']:
330            self.assertEqual(out.count(msg), 3)
331        for msg in [ae_msg, at_msg]:
332            self.assertEqual(out.count(msg), 1)
333
334    def testStdErrLookedUpAtInstantiationTime(self):
335        # see issue 10786
336        old_stderr = sys.stderr
337        f = io.StringIO()
338        sys.stderr = f
339        try:
340            runner = unittest.TextTestRunner()
341            self.assertTrue(runner.stream.stream is f)
342        finally:
343            sys.stderr = old_stderr
344
345    def testSpecifiedStreamUsed(self):
346        # see issue 10786
347        f = io.StringIO()
348        runner = unittest.TextTestRunner(f)
349        self.assertTrue(runner.stream.stream is f)
350
351
352if __name__ == "__main__":
353    unittest.main()
354