mirror of
https://github.com/python/cpython.git
synced 2025-07-23 11:15:24 +00:00

Rather than supporting dev mode directly in the warnings module, this instead adjusts the initialisation code to add an extra 'default' entry to sys.warnoptions when dev mode is enabled. This ensures that dev mode behaves *exactly* as if `-Wdefault` had been passed on the command line, including in the way it interacts with `sys.warnoptions`, and with other command line flags like `-bb`. Fix also bpo-20361: have -b & -bb options take precedence over any other warnings options. Patch written by Nick Coghlan, with minor modifications of Victor Stinner.
353 lines
12 KiB
Python
353 lines
12 KiB
Python
import io
|
|
import os
|
|
import sys
|
|
import pickle
|
|
import subprocess
|
|
|
|
import unittest
|
|
from unittest.case import _Outcome
|
|
|
|
from unittest.test.support import (LoggingResult,
|
|
ResultWithNoStartTestRunStopTestRun)
|
|
|
|
|
|
class TestCleanUp(unittest.TestCase):
|
|
|
|
def testCleanUp(self):
|
|
class TestableTest(unittest.TestCase):
|
|
def testNothing(self):
|
|
pass
|
|
|
|
test = TestableTest('testNothing')
|
|
self.assertEqual(test._cleanups, [])
|
|
|
|
cleanups = []
|
|
|
|
def cleanup1(*args, **kwargs):
|
|
cleanups.append((1, args, kwargs))
|
|
|
|
def cleanup2(*args, **kwargs):
|
|
cleanups.append((2, args, kwargs))
|
|
|
|
test.addCleanup(cleanup1, 1, 2, 3, four='hello', five='goodbye')
|
|
test.addCleanup(cleanup2)
|
|
|
|
self.assertEqual(test._cleanups,
|
|
[(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')),
|
|
(cleanup2, (), {})])
|
|
|
|
self.assertTrue(test.doCleanups())
|
|
self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
|
|
|
|
def testCleanUpWithErrors(self):
|
|
class TestableTest(unittest.TestCase):
|
|
def testNothing(self):
|
|
pass
|
|
|
|
test = TestableTest('testNothing')
|
|
outcome = test._outcome = _Outcome()
|
|
|
|
exc1 = Exception('foo')
|
|
exc2 = Exception('bar')
|
|
def cleanup1():
|
|
raise exc1
|
|
|
|
def cleanup2():
|
|
raise exc2
|
|
|
|
test.addCleanup(cleanup1)
|
|
test.addCleanup(cleanup2)
|
|
|
|
self.assertFalse(test.doCleanups())
|
|
self.assertFalse(outcome.success)
|
|
|
|
((_, (Type1, instance1, _)),
|
|
(_, (Type2, instance2, _))) = reversed(outcome.errors)
|
|
self.assertEqual((Type1, instance1), (Exception, exc1))
|
|
self.assertEqual((Type2, instance2), (Exception, exc2))
|
|
|
|
def testCleanupInRun(self):
|
|
blowUp = False
|
|
ordering = []
|
|
|
|
class TestableTest(unittest.TestCase):
|
|
def setUp(self):
|
|
ordering.append('setUp')
|
|
if blowUp:
|
|
raise Exception('foo')
|
|
|
|
def testNothing(self):
|
|
ordering.append('test')
|
|
|
|
def tearDown(self):
|
|
ordering.append('tearDown')
|
|
|
|
test = TestableTest('testNothing')
|
|
|
|
def cleanup1():
|
|
ordering.append('cleanup1')
|
|
def cleanup2():
|
|
ordering.append('cleanup2')
|
|
test.addCleanup(cleanup1)
|
|
test.addCleanup(cleanup2)
|
|
|
|
def success(some_test):
|
|
self.assertEqual(some_test, test)
|
|
ordering.append('success')
|
|
|
|
result = unittest.TestResult()
|
|
result.addSuccess = success
|
|
|
|
test.run(result)
|
|
self.assertEqual(ordering, ['setUp', 'test', 'tearDown',
|
|
'cleanup2', 'cleanup1', 'success'])
|
|
|
|
blowUp = True
|
|
ordering = []
|
|
test = TestableTest('testNothing')
|
|
test.addCleanup(cleanup1)
|
|
test.run(result)
|
|
self.assertEqual(ordering, ['setUp', 'cleanup1'])
|
|
|
|
def testTestCaseDebugExecutesCleanups(self):
|
|
ordering = []
|
|
|
|
class TestableTest(unittest.TestCase):
|
|
def setUp(self):
|
|
ordering.append('setUp')
|
|
self.addCleanup(cleanup1)
|
|
|
|
def testNothing(self):
|
|
ordering.append('test')
|
|
|
|
def tearDown(self):
|
|
ordering.append('tearDown')
|
|
|
|
test = TestableTest('testNothing')
|
|
|
|
def cleanup1():
|
|
ordering.append('cleanup1')
|
|
test.addCleanup(cleanup2)
|
|
def cleanup2():
|
|
ordering.append('cleanup2')
|
|
|
|
test.debug()
|
|
self.assertEqual(ordering, ['setUp', 'test', 'tearDown', 'cleanup1', 'cleanup2'])
|
|
|
|
|
|
class Test_TextTestRunner(unittest.TestCase):
|
|
"""Tests for TextTestRunner."""
|
|
|
|
def setUp(self):
|
|
# clean the environment from pre-existing PYTHONWARNINGS to make
|
|
# test_warnings results consistent
|
|
self.pythonwarnings = os.environ.get('PYTHONWARNINGS')
|
|
if self.pythonwarnings:
|
|
del os.environ['PYTHONWARNINGS']
|
|
|
|
def tearDown(self):
|
|
# bring back pre-existing PYTHONWARNINGS if present
|
|
if self.pythonwarnings:
|
|
os.environ['PYTHONWARNINGS'] = self.pythonwarnings
|
|
|
|
def test_init(self):
|
|
runner = unittest.TextTestRunner()
|
|
self.assertFalse(runner.failfast)
|
|
self.assertFalse(runner.buffer)
|
|
self.assertEqual(runner.verbosity, 1)
|
|
self.assertEqual(runner.warnings, None)
|
|
self.assertTrue(runner.descriptions)
|
|
self.assertEqual(runner.resultclass, unittest.TextTestResult)
|
|
self.assertFalse(runner.tb_locals)
|
|
|
|
def test_multiple_inheritance(self):
|
|
class AResult(unittest.TestResult):
|
|
def __init__(self, stream, descriptions, verbosity):
|
|
super(AResult, self).__init__(stream, descriptions, verbosity)
|
|
|
|
class ATextResult(unittest.TextTestResult, AResult):
|
|
pass
|
|
|
|
# This used to raise an exception due to TextTestResult not passing
|
|
# on arguments in its __init__ super call
|
|
ATextResult(None, None, 1)
|
|
|
|
def testBufferAndFailfast(self):
|
|
class Test(unittest.TestCase):
|
|
def testFoo(self):
|
|
pass
|
|
result = unittest.TestResult()
|
|
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True,
|
|
buffer=True)
|
|
# Use our result object
|
|
runner._makeResult = lambda: result
|
|
runner.run(Test('testFoo'))
|
|
|
|
self.assertTrue(result.failfast)
|
|
self.assertTrue(result.buffer)
|
|
|
|
def test_locals(self):
|
|
runner = unittest.TextTestRunner(stream=io.StringIO(), tb_locals=True)
|
|
result = runner.run(unittest.TestSuite())
|
|
self.assertEqual(True, result.tb_locals)
|
|
|
|
def testRunnerRegistersResult(self):
|
|
class Test(unittest.TestCase):
|
|
def testFoo(self):
|
|
pass
|
|
originalRegisterResult = unittest.runner.registerResult
|
|
def cleanup():
|
|
unittest.runner.registerResult = originalRegisterResult
|
|
self.addCleanup(cleanup)
|
|
|
|
result = unittest.TestResult()
|
|
runner = unittest.TextTestRunner(stream=io.StringIO())
|
|
# Use our result object
|
|
runner._makeResult = lambda: result
|
|
|
|
self.wasRegistered = 0
|
|
def fakeRegisterResult(thisResult):
|
|
self.wasRegistered += 1
|
|
self.assertEqual(thisResult, result)
|
|
unittest.runner.registerResult = fakeRegisterResult
|
|
|
|
runner.run(unittest.TestSuite())
|
|
self.assertEqual(self.wasRegistered, 1)
|
|
|
|
def test_works_with_result_without_startTestRun_stopTestRun(self):
|
|
class OldTextResult(ResultWithNoStartTestRunStopTestRun):
|
|
separator2 = ''
|
|
def printErrors(self):
|
|
pass
|
|
|
|
class Runner(unittest.TextTestRunner):
|
|
def __init__(self):
|
|
super(Runner, self).__init__(io.StringIO())
|
|
|
|
def _makeResult(self):
|
|
return OldTextResult()
|
|
|
|
runner = Runner()
|
|
runner.run(unittest.TestSuite())
|
|
|
|
def test_startTestRun_stopTestRun_called(self):
|
|
class LoggingTextResult(LoggingResult):
|
|
separator2 = ''
|
|
def printErrors(self):
|
|
pass
|
|
|
|
class LoggingRunner(unittest.TextTestRunner):
|
|
def __init__(self, events):
|
|
super(LoggingRunner, self).__init__(io.StringIO())
|
|
self._events = events
|
|
|
|
def _makeResult(self):
|
|
return LoggingTextResult(self._events)
|
|
|
|
events = []
|
|
runner = LoggingRunner(events)
|
|
runner.run(unittest.TestSuite())
|
|
expected = ['startTestRun', 'stopTestRun']
|
|
self.assertEqual(events, expected)
|
|
|
|
def test_pickle_unpickle(self):
|
|
# Issue #7197: a TextTestRunner should be (un)pickleable. This is
|
|
# required by test_multiprocessing under Windows (in verbose mode).
|
|
stream = io.StringIO("foo")
|
|
runner = unittest.TextTestRunner(stream)
|
|
for protocol in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
|
s = pickle.dumps(runner, protocol)
|
|
obj = pickle.loads(s)
|
|
# StringIO objects never compare equal, a cheap test instead.
|
|
self.assertEqual(obj.stream.getvalue(), stream.getvalue())
|
|
|
|
def test_resultclass(self):
|
|
def MockResultClass(*args):
|
|
return args
|
|
STREAM = object()
|
|
DESCRIPTIONS = object()
|
|
VERBOSITY = object()
|
|
runner = unittest.TextTestRunner(STREAM, DESCRIPTIONS, VERBOSITY,
|
|
resultclass=MockResultClass)
|
|
self.assertEqual(runner.resultclass, MockResultClass)
|
|
|
|
expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
|
|
self.assertEqual(runner._makeResult(), expectedresult)
|
|
|
|
def test_warnings(self):
|
|
"""
|
|
Check that warnings argument of TextTestRunner correctly affects the
|
|
behavior of the warnings.
|
|
"""
|
|
# see #10535 and the _test_warnings file for more information
|
|
|
|
def get_parse_out_err(p):
|
|
return [b.splitlines() for b in p.communicate()]
|
|
opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
cwd=os.path.dirname(__file__))
|
|
ae_msg = b'Please use assertEqual instead.'
|
|
at_msg = b'Please use assertTrue instead.'
|
|
|
|
# no args -> all the warnings are printed, unittest warnings only once
|
|
p = subprocess.Popen([sys.executable, '-E', '_test_warnings.py'], **opts)
|
|
with p:
|
|
out, err = get_parse_out_err(p)
|
|
self.assertIn(b'OK', err)
|
|
# check that the total number of warnings in the output is correct
|
|
self.assertEqual(len(out), 12)
|
|
# check that the numbers of the different kind of warnings is correct
|
|
for msg in [b'dw', b'iw', b'uw']:
|
|
self.assertEqual(out.count(msg), 3)
|
|
for msg in [ae_msg, at_msg, b'rw']:
|
|
self.assertEqual(out.count(msg), 1)
|
|
|
|
args_list = (
|
|
# passing 'ignore' as warnings arg -> no warnings
|
|
[sys.executable, '_test_warnings.py', 'ignore'],
|
|
# -W doesn't affect the result if the arg is passed
|
|
[sys.executable, '-Wa', '_test_warnings.py', 'ignore'],
|
|
# -W affects the result if the arg is not passed
|
|
[sys.executable, '-Wi', '_test_warnings.py']
|
|
)
|
|
# in all these cases no warnings are printed
|
|
for args in args_list:
|
|
p = subprocess.Popen(args, **opts)
|
|
with p:
|
|
out, err = get_parse_out_err(p)
|
|
self.assertIn(b'OK', err)
|
|
self.assertEqual(len(out), 0)
|
|
|
|
|
|
# passing 'always' as warnings arg -> all the warnings printed,
|
|
# unittest warnings only once
|
|
p = subprocess.Popen([sys.executable, '_test_warnings.py', 'always'],
|
|
**opts)
|
|
with p:
|
|
out, err = get_parse_out_err(p)
|
|
self.assertIn(b'OK', err)
|
|
self.assertEqual(len(out), 14)
|
|
for msg in [b'dw', b'iw', b'uw', b'rw']:
|
|
self.assertEqual(out.count(msg), 3)
|
|
for msg in [ae_msg, at_msg]:
|
|
self.assertEqual(out.count(msg), 1)
|
|
|
|
def testStdErrLookedUpAtInstantiationTime(self):
|
|
# see issue 10786
|
|
old_stderr = sys.stderr
|
|
f = io.StringIO()
|
|
sys.stderr = f
|
|
try:
|
|
runner = unittest.TextTestRunner()
|
|
self.assertTrue(runner.stream.stream is f)
|
|
finally:
|
|
sys.stderr = old_stderr
|
|
|
|
def testSpecifiedStreamUsed(self):
|
|
# see issue 10786
|
|
f = io.StringIO()
|
|
runner = unittest.TextTestRunner(f)
|
|
self.assertTrue(runner.stream.stream is f)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|