summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2010-04-11 20:43:16 (GMT)
committerBenjamin Peterson <benjamin@python.org>2010-04-11 20:43:16 (GMT)
commitb48af54ff77f72a26ee978ef601ac17a7a5798f6 (patch)
tree2030f74eb5ee542c0a60113222b195cc3a9e584d /Lib
parentfc3c9cd7939fe12e8298c2dd854b6e50e9353283 (diff)
downloadcpython-b48af54ff77f72a26ee978ef601ac17a7a5798f6.zip
cpython-b48af54ff77f72a26ee978ef601ac17a7a5798f6.tar.gz
cpython-b48af54ff77f72a26ee978ef601ac17a7a5798f6.tar.bz2
Merged revisions 79464,79471,79623,79626,79630,79632,79643,79648-79649,79679,79685,79711,79761,79774,79777,79792-79794,79877,79898-79900 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r79464 | michael.foord | 2010-03-27 07:55:19 -0500 (Sat, 27 Mar 2010) | 1 line A fix for running unittest tests on platforms without the audioop module (e.g. jython and IronPython) ........ r79471 | michael.foord | 2010-03-27 14:10:11 -0500 (Sat, 27 Mar 2010) | 4 lines Addition of delta keyword argument to unittest.TestCase.assertAlmostEquals and assertNotAlmostEquals This allows the comparison of objects by specifying a maximum difference; this includes the comparing of non-numeric objects that don't support rounding. ........ r79623 | michael.foord | 2010-04-02 16:42:47 -0500 (Fri, 02 Apr 2010) | 1 line Addition of -b command line option to unittest for buffering stdout and stderr during test runs. ........ r79626 | michael.foord | 2010-04-02 17:08:29 -0500 (Fri, 02 Apr 2010) | 1 line TestResult stores original sys.stdout and tests no longer use sys.__stdout__ (etc) in tests for unittest -b command line option ........ r79630 | michael.foord | 2010-04-02 17:30:56 -0500 (Fri, 02 Apr 2010) | 1 line unittest tests no longer replace the sys.stdout put in place by regrtest ........ r79632 | michael.foord | 2010-04-02 17:55:59 -0500 (Fri, 02 Apr 2010) | 1 line Issue #8038: Addition of unittest.TestCase.assertNotRegexpMatches ........ r79643 | michael.foord | 2010-04-02 20:15:21 -0500 (Fri, 02 Apr 2010) | 1 line Support dotted module names for test discovery paths in unittest. Issue 8038. ........ r79648 | michael.foord | 2010-04-02 21:21:39 -0500 (Fri, 02 Apr 2010) | 1 line Cross platform unittest.TestResult newline handling when buffering stdout / stderr. ........ r79649 | michael.foord | 2010-04-02 21:33:55 -0500 (Fri, 02 Apr 2010) | 1 line Another attempt at a fix for unittest.test.test_result for windows line endings ........ r79679 | michael.foord | 2010-04-03 09:52:18 -0500 (Sat, 03 Apr 2010) | 1 line Adding -b command line option to the unittest usage message. ........ r79685 | michael.foord | 2010-04-03 10:20:00 -0500 (Sat, 03 Apr 2010) | 1 line Minor tweak to unittest command line usage message ........ r79711 | michael.foord | 2010-04-03 12:03:11 -0500 (Sat, 03 Apr 2010) | 1 line Documenting new features in unittest ........ r79761 | michael.foord | 2010-04-04 17:41:54 -0500 (Sun, 04 Apr 2010) | 1 line unittest documentation formatting changes ........ r79774 | michael.foord | 2010-04-04 18:28:44 -0500 (Sun, 04 Apr 2010) | 1 line Adding documentation for new unittest.main() parameters ........ r79777 | michael.foord | 2010-04-04 19:39:50 -0500 (Sun, 04 Apr 2010) | 1 line Document signal handling functions in unittest.rst ........ r79792 | michael.foord | 2010-04-05 05:26:26 -0500 (Mon, 05 Apr 2010) | 1 line Documentation fixes for unittest ........ r79793 | michael.foord | 2010-04-05 05:28:27 -0500 (Mon, 05 Apr 2010) | 1 line Furterh documentation fix for unittest.rst ........ r79794 | michael.foord | 2010-04-05 05:30:14 -0500 (Mon, 05 Apr 2010) | 1 line Further documentation fix for unittest.rst ........ r79877 | michael.foord | 2010-04-06 18:18:16 -0500 (Tue, 06 Apr 2010) | 1 line Fix module directory finding logic for dotted paths in unittest test discovery. ........ r79898 | michael.foord | 2010-04-07 18:04:22 -0500 (Wed, 07 Apr 2010) | 1 line unittest.result.TestResult does not create its buffers until they're used. It uses StringIO not cStringIO. Issue 8333. ........ r79899 | michael.foord | 2010-04-07 19:04:24 -0500 (Wed, 07 Apr 2010) | 1 line Switch regrtest to use StringIO instead of cStringIO for test_multiprocessing on Windows. Issue 8333. ........ r79900 | michael.foord | 2010-04-07 23:33:20 -0500 (Wed, 07 Apr 2010) | 1 line Correction of unittest documentation typos and omissions ........
Diffstat (limited to 'Lib')
-rwxr-xr-xLib/test/regrtest.py4
-rw-r--r--Lib/test/test_argparse.py13
-rw-r--r--Lib/unittest/case.py71
-rw-r--r--Lib/unittest/loader.py39
-rw-r--r--Lib/unittest/main.py41
-rw-r--r--Lib/unittest/result.py64
-rw-r--r--Lib/unittest/runner.py4
-rw-r--r--Lib/unittest/test/dummy.py1
-rw-r--r--Lib/unittest/test/test_assertions.py34
-rw-r--r--Lib/unittest/test/test_break.py10
-rw-r--r--Lib/unittest/test/test_discovery.py11
-rw-r--r--Lib/unittest/test/test_loader.py20
-rw-r--r--Lib/unittest/test/test_result.py132
13 files changed, 385 insertions, 59 deletions
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index f3c2a5f..fdcaf88 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -880,6 +880,10 @@ def runtest_inner(test, verbose, quiet,
testdir=None, huntrleaks=False, debug=False):
support.unload(test)
testdir = findtestdir(testdir)
+ if verbose:
+ capture_stdout = None
+ else:
+ capture_stdout = io.StringIO()
test_time = 0.0
refleak = False # True if the test leaked references.
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 85513a5..f13c622 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -12,6 +12,8 @@ import argparse
from io import StringIO
from test import support
+class StdIOBuffer(StringIO):
+ pass
class TestCase(unittest.TestCase):
@@ -25,6 +27,7 @@ class TestCase(unittest.TestCase):
super(TestCase, self).assertEqual(obj1, obj2)
+
class TempDirMixin(object):
def setUp(self):
@@ -81,15 +84,15 @@ def stderr_to_parser_error(parse_args, *args, **kwargs):
# if this is being called recursively and stderr or stdout is already being
# redirected, simply call the function and let the enclosing function
# catch the exception
- if isinstance(sys.stderr, StringIO) or isinstance(sys.stdout, StringIO):
+ if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
return parse_args(*args, **kwargs)
# if this is not being called recursively, redirect stderr and
# use it as the ArgumentParserError message
old_stdout = sys.stdout
old_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
+ sys.stdout = StdIOBuffer()
+ sys.stderr = StdIOBuffer()
try:
try:
result = parse_args(*args, **kwargs)
@@ -2634,7 +2637,7 @@ class TestHelpFormattingMetaclass(type):
parser = self._get_parser(tester)
print_ = getattr(parser, 'print_%s' % self.func_suffix)
old_stream = getattr(sys, self.std_name)
- setattr(sys, self.std_name, StringIO())
+ setattr(sys, self.std_name, StdIOBuffer())
try:
print_()
parser_text = getattr(sys, self.std_name).getvalue()
@@ -2645,7 +2648,7 @@ class TestHelpFormattingMetaclass(type):
def test_print_file(self, tester):
parser = self._get_parser(tester)
print_ = getattr(parser, 'print_%s' % self.func_suffix)
- sfile = StringIO()
+ sfile = StdIOBuffer()
print_(sfile)
parser_text = sfile.getvalue()
self._test(tester, parser_text)
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index ac5d1ec..366fe87 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -502,10 +502,12 @@ class TestCase(object):
safe_repr(second)))
raise self.failureException(msg)
- def assertAlmostEqual(self, first, second, *, places=7, msg=None):
+ def assertAlmostEqual(self, first, second, *, places=None, msg=None,
+ delta=None):
"""Fail if the two objects are unequal as determined by their
difference rounded to the given number of decimal places
- (default 7) and comparing to zero.
+ (default 7) and comparing to zero, or by comparing that the
+ between the two objects is more than the given delta.
Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit).
@@ -514,31 +516,62 @@ class TestCase(object):
compare almost equal.
"""
if first == second:
- # shortcut for inf
+ # shortcut
return
- if round(abs(second-first), places) != 0:
+ if delta is not None and places is not None:
+ raise TypeError("specify delta or places not both")
+
+ if delta is not None:
+ if abs(first - second) <= delta:
+ return
+
+ standardMsg = '%s != %s within %s delta' % (safe_repr(first),
+ safe_repr(second),
+ safe_repr(delta))
+ else:
+ if places is None:
+ places = 7
+
+ if round(abs(second-first), places) == 0:
+ return
+
standardMsg = '%s != %s within %r places' % (safe_repr(first),
safe_repr(second),
places)
- msg = self._formatMessage(msg, standardMsg)
- raise self.failureException(msg)
+ msg = self._formatMessage(msg, standardMsg)
+ raise self.failureException(msg)
- def assertNotAlmostEqual(self, first, second, *, places=7, msg=None):
+ def assertNotAlmostEqual(self, first, second, *, places=None, msg=None,
+ delta=None):
"""Fail if the two objects are equal as determined by their
difference rounded to the given number of decimal places
- (default 7) and comparing to zero.
+ (default 7) and comparing to zero, or by comparing that the
+ between the two objects is less than the given delta.
Note that decimal places (from zero) are usually not the same
as significant digits (measured from the most signficant digit).
Objects that are equal automatically fail.
"""
- if (first == second) or round(abs(second-first), places) == 0:
+ if delta is not None and places is not None:
+ raise TypeError("specify delta or places not both")
+ if delta is not None:
+ if not (first == second) and abs(first - second) > delta:
+ return
+ standardMsg = '%s == %s within %s delta' % (safe_repr(first),
+ safe_repr(second),
+ safe_repr(delta))
+ else:
+ if places is None:
+ places = 7
+ if not (first == second) and round(abs(second-first), places) != 0:
+ return
standardMsg = '%s == %s within %r places' % (safe_repr(first),
- safe_repr(second),
- places)
- msg = self._formatMessage(msg, standardMsg)
- raise self.failureException(msg)
+ safe_repr(second),
+ places)
+
+ msg = self._formatMessage(msg, standardMsg)
+ raise self.failureException(msg)
# Synonyms for assertion methods
@@ -967,6 +1000,18 @@ class TestCase(object):
msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
raise self.failureException(msg)
+ def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
+ if isinstance(unexpected_regexp, (str, bytes)):
+ unexpected_regexp = re.compile(unexpected_regexp)
+ match = unexpected_regexp.search(text)
+ if match:
+ msg = msg or "Regexp matched"
+ msg = '%s: %r matches %r in %r' % (msg,
+ text[match.start():match.end()],
+ unexpected_regexp.pattern,
+ text)
+ raise self.failureException(msg)
+
class FunctionTestCase(TestCase):
"""A test case that wraps a test function.
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index f00f38d..a45dffa 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -166,27 +166,58 @@ class TestLoader(object):
packages can continue discovery themselves. top_level_dir is stored so
load_tests does not need to pass this argument in to loader.discover().
"""
+ set_implicit_top = False
if top_level_dir is None and self._top_level_dir is not None:
# make top_level_dir optional if called from load_tests in a package
top_level_dir = self._top_level_dir
elif top_level_dir is None:
+ set_implicit_top = True
top_level_dir = start_dir
- top_level_dir = os.path.abspath(os.path.normpath(top_level_dir))
- start_dir = os.path.abspath(os.path.normpath(start_dir))
+ top_level_dir = os.path.abspath(top_level_dir)
if not top_level_dir in sys.path:
# all test modules must be importable from the top level directory
sys.path.append(top_level_dir)
self._top_level_dir = top_level_dir
- if start_dir != top_level_dir and not os.path.isfile(os.path.join(start_dir, '__init__.py')):
- # what about __init__.pyc or pyo (etc)
+ is_not_importable = False
+ if os.path.isdir(os.path.abspath(start_dir)):
+ start_dir = os.path.abspath(start_dir)
+ if start_dir != top_level_dir:
+ is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py'))
+ else:
+ # support for discovery from dotted module names
+ try:
+ __import__(start_dir)
+ except ImportError:
+ is_not_importable = True
+ else:
+ the_module = sys.modules[start_dir]
+ top_part = start_dir.split('.')[0]
+ start_dir = os.path.abspath(os.path.dirname((the_module.__file__)))
+ if set_implicit_top:
+ self._top_level_dir = self._get_directory_containing_module(top_part)
+ sys.path.remove(top_level_dir)
+
+ if is_not_importable:
raise ImportError('Start directory is not importable: %r' % start_dir)
tests = list(self._find_tests(start_dir, pattern))
return self.suiteClass(tests)
+ def _get_directory_containing_module(self, module_name):
+ module = sys.modules[module_name]
+ full_path = os.path.abspath(module.__file__)
+
+ if os.path.basename(full_path).lower().startswith('__init__.py'):
+ return os.path.dirname(os.path.dirname(full_path))
+ else:
+ # here we have been given a module rather than a package - so
+ # all we can do is search the *same* directory the module is in
+ # should an exception be raised instead
+ return os.path.dirname(full_path)
+
def _get_name_from_path(self, path):
path = os.path.splitext(os.path.normpath(path))[0]
diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py
index 3e659ab..2f488e1 100644
--- a/Lib/unittest/main.py
+++ b/Lib/unittest/main.py
@@ -9,9 +9,9 @@ from .signals import installHandler
__unittest = True
-
-FAILFAST = " -f, --failfast Stop on first failure\n"
-CATCHBREAK = " -c, --catch Catch control-C and display results\n"
+FAILFAST = " -f, --failfast Stop on first failure\n"
+CATCHBREAK = " -c, --catch Catch control-C and display results\n"
+BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n"
USAGE_AS_MAIN = """\
Usage: %(progName)s [options] [tests]
@@ -20,7 +20,7 @@ Options:
-h, --help Show this message
-v, --verbose Verbose output
-q, --quiet Minimal output
-%(failfast)s%(catchbreak)s
+%(failfast)s%(catchbreak)s%(buffer)s
Examples:
%(progName)s test_module - run tests from test_module
%(progName)s test_module.TestClass - run tests from
@@ -34,7 +34,7 @@ Alternative Usage: %(progName)s discover [options]
Options:
-v, --verbose Verbose output
-%(failfast)s%(catchbreak)s -s directory Directory to start discovery ('.' default)
+%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default)
-p pattern Pattern to match test files ('test*.py' default)
-t directory Top level directory of project (default to
start directory)
@@ -50,7 +50,7 @@ Options:
-h, --help Show this message
-v, --verbose Verbose output
-q, --quiet Minimal output
-%(failfast)s%(catchbreak)s
+%(failfast)s%(catchbreak)s%(buffer)s
Examples:
%(progName)s - run default set of tests
%(progName)s MyTestSuite - run suite 'MyTestSuite'
@@ -68,12 +68,12 @@ class TestProgram(object):
USAGE = USAGE_FROM_MODULE
# defaults for testing
- failfast = catchbreak = None
+ failfast = catchbreak = buffer = None
def __init__(self, module='__main__', defaultTest=None,
argv=None, testRunner=None,
testLoader=loader.defaultTestLoader, exit=True,
- verbosity=1, failfast=None, catchbreak=None):
+ verbosity=1, failfast=None, catchbreak=None, buffer=None):
if isinstance(module, str):
self.module = __import__(module)
for part in module.split('.')[1:]:
@@ -87,6 +87,7 @@ class TestProgram(object):
self.failfast = failfast
self.catchbreak = catchbreak
self.verbosity = verbosity
+ self.buffer = buffer
self.defaultTest = defaultTest
self.testRunner = testRunner
self.testLoader = testLoader
@@ -97,11 +98,14 @@ class TestProgram(object):
def usageExit(self, msg=None):
if msg:
print(msg)
- usage = {'progName': self.progName, 'catchbreak': '', 'failfast': ''}
+ usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '',
+ 'buffer': ''}
if self.failfast != False:
usage['failfast'] = FAILFAST
if self.catchbreak != False:
usage['catchbreak'] = CATCHBREAK
+ if self.buffer != False:
+ usage['buffer'] = BUFFEROUTPUT
print(self.USAGE % usage)
sys.exit(2)
@@ -111,9 +115,9 @@ class TestProgram(object):
return
import getopt
- long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch']
+ long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer']
try:
- options, args = getopt.getopt(argv[1:], 'hHvqfc', long_opts)
+ options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts)
for opt, value in options:
if opt in ('-h','-H','--help'):
self.usageExit()
@@ -129,6 +133,10 @@ class TestProgram(object):
if self.catchbreak is None:
self.catchbreak = True
# Should this raise an exception if -c is not valid?
+ if opt in ('-b','--buffer'):
+ if self.buffer is None:
+ self.buffer = True
+ # Should this raise an exception if -b is not valid?
if len(args) == 0 and self.defaultTest is None:
# createTests will load tests from self.module
self.testNames = None
@@ -164,6 +172,10 @@ class TestProgram(object):
parser.add_option('-c', '--catch', dest='catchbreak', default=False,
help='Catch ctrl-C and display results so far',
action='store_true')
+ if self.buffer != False:
+ parser.add_option('-b', '--buffer', dest='buffer', default=False,
+ help='Buffer stdout and stderr during tests',
+ action='store_true')
parser.add_option('-s', '--start-directory', dest='start', default='.',
help="Directory to start discovery ('.' default)")
parser.add_option('-p', '--pattern', dest='pattern', default='test*.py',
@@ -184,6 +196,8 @@ class TestProgram(object):
self.failfast = options.failfast
if self.catchbreak is None:
self.catchbreak = options.catchbreak
+ if self.buffer is None:
+ self.buffer = options.buffer
if options.verbose:
self.verbosity = 2
@@ -203,9 +217,10 @@ class TestProgram(object):
if isinstance(self.testRunner, type):
try:
testRunner = self.testRunner(verbosity=self.verbosity,
- failfast=self.failfast)
+ failfast=self.failfast,
+ buffer=self.buffer)
except TypeError:
- # didn't accept the verbosity or failfast arguments
+ # didn't accept the verbosity, buffer or failfast arguments
testRunner = self.testRunner()
else:
# it is assumed to be a TestRunner instance
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py
index ec80e8e..92b1f91 100644
--- a/Lib/unittest/result.py
+++ b/Lib/unittest/result.py
@@ -1,5 +1,8 @@
"""Test result object"""
+import os
+import io
+import sys
import traceback
from . import util
@@ -15,6 +18,10 @@ def failfast(method):
return method(self, *args, **kw)
return inner
+STDOUT_LINE = '\nStdout:\n%s'
+STDERR_LINE = '\nStderr:\n%s'
+
+
class TestResult(object):
"""Holder for test result information.
@@ -37,6 +44,12 @@ class TestResult(object):
self.expectedFailures = []
self.unexpectedSuccesses = []
self.shouldStop = False
+ self.buffer = False
+ self._stdout_buffer = None
+ self._stderr_buffer = None
+ self._original_stdout = sys.stdout
+ self._original_stderr = sys.stderr
+ self._mirrorOutput = False
def printErrors(self):
"Called by TestRunner after test run"
@@ -44,6 +57,13 @@ class TestResult(object):
def startTest(self, test):
"Called when the given test is about to be run"
self.testsRun += 1
+ self._mirrorOutput = False
+ if self.buffer:
+ if self._stderr_buffer is None:
+ self._stderr_buffer = io.StringIO()
+ self._stdout_buffer = io.StringIO()
+ sys.stdout = self._stdout_buffer
+ sys.stderr = self._stderr_buffer
def startTestRun(self):
"""Called once before any tests are executed.
@@ -53,6 +73,26 @@ class TestResult(object):
def stopTest(self, test):
"""Called when the given test has been run"""
+ if self.buffer:
+ if self._mirrorOutput:
+ output = sys.stdout.getvalue()
+ error = sys.stderr.getvalue()
+ if output:
+ if not output.endswith('\n'):
+ output += '\n'
+ self._original_stdout.write(STDOUT_LINE % output)
+ if error:
+ if not error.endswith('\n'):
+ error += '\n'
+ self._original_stderr.write(STDERR_LINE % error)
+
+ sys.stdout = self._original_stdout
+ sys.stderr = self._original_stderr
+ self._stdout_buffer.seek(0)
+ self._stdout_buffer.truncate()
+ self._stderr_buffer.seek(0)
+ self._stderr_buffer.truncate()
+ self._mirrorOutput = False
def stopTestRun(self):
"""Called once after all tests are executed.
@@ -66,12 +106,14 @@ class TestResult(object):
returned by sys.exc_info().
"""
self.errors.append((test, self._exc_info_to_string(err, test)))
+ self._mirrorOutput = True
@failfast
def addFailure(self, test, err):
"""Called when an error has occurred. 'err' is a tuple of values as
returned by sys.exc_info()."""
self.failures.append((test, self._exc_info_to_string(err, test)))
+ self._mirrorOutput = True
def addSuccess(self, test):
"Called when a test has completed successfully"
@@ -105,11 +147,29 @@ class TestResult(object):
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
+
if exctype is test.failureException:
# Skip assert*() traceback levels
length = self._count_relevant_tb_levels(tb)
- return ''.join(traceback.format_exception(exctype, value, tb, length))
- return ''.join(traceback.format_exception(exctype, value, tb))
+ msgLines = traceback.format_exception(exctype, value, tb, length)
+ else:
+ chain = exctype is not None
+ msgLines = traceback.format_exception(exctype, value, tb,
+ chain=chain)
+
+ if self.buffer:
+ output = sys.stdout.getvalue()
+ error = sys.stderr.getvalue()
+ if output:
+ if not output.endswith('\n'):
+ output += '\n'
+ msgLines.append(STDOUT_LINE % output)
+ if error:
+ if not error.endswith('\n'):
+ error += '\n'
+ msgLines.append(STDERR_LINE % error)
+ return ''.join(msgLines)
+
def _is_relevant_tb_level(self, tb):
return '__unittest' in tb.tb_frame.f_globals
diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py
index 8065642..f13d623f 100644
--- a/Lib/unittest/runner.py
+++ b/Lib/unittest/runner.py
@@ -125,11 +125,12 @@ class TextTestRunner(object):
resultclass = TextTestResult
def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1,
- failfast=False, resultclass=None):
+ failfast=False, buffer=False, resultclass=None):
self.stream = _WritelnDecorator(stream)
self.descriptions = descriptions
self.verbosity = verbosity
self.failfast = failfast
+ self.buffer = buffer
if resultclass is not None:
self.resultclass = resultclass
@@ -141,6 +142,7 @@ class TextTestRunner(object):
result = self._makeResult()
registerResult(result)
result.failfast = self.failfast
+ result.buffer = self.buffer
startTime = time.time()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
diff --git a/Lib/unittest/test/dummy.py b/Lib/unittest/test/dummy.py
new file mode 100644
index 0000000..e4f14e4
--- /dev/null
+++ b/Lib/unittest/test/dummy.py
@@ -0,0 +1 @@
+# Empty module for testing the loading of modules
diff --git a/Lib/unittest/test/test_assertions.py b/Lib/unittest/test/test_assertions.py
index fe65849..06b1ab8e5 100644
--- a/Lib/unittest/test/test_assertions.py
+++ b/Lib/unittest/test/test_assertions.py
@@ -1,3 +1,5 @@
+import datetime
+
import unittest
@@ -25,6 +27,28 @@ class Test_Assertions(unittest.TestCase):
self.assertRaises(self.failureException, self.assertNotAlmostEqual,
float('inf'), float('inf'))
+ def test_AmostEqualWithDelta(self):
+ self.assertAlmostEqual(1.1, 1.0, delta=0.5)
+ self.assertAlmostEqual(1.0, 1.1, delta=0.5)
+ self.assertNotAlmostEqual(1.1, 1.0, delta=0.05)
+ self.assertNotAlmostEqual(1.0, 1.1, delta=0.05)
+
+ self.assertRaises(self.failureException, self.assertAlmostEqual,
+ 1.1, 1.0, delta=0.05)
+ self.assertRaises(self.failureException, self.assertNotAlmostEqual,
+ 1.1, 1.0, delta=0.5)
+
+ self.assertRaises(TypeError, self.assertAlmostEqual,
+ 1.1, 1.0, places=2, delta=2)
+ self.assertRaises(TypeError, self.assertNotAlmostEqual,
+ 1.1, 1.0, places=2, delta=2)
+
+ first = datetime.datetime.now()
+ second = first + datetime.timedelta(seconds=10)
+ self.assertAlmostEqual(first, second,
+ delta=datetime.timedelta(seconds=20))
+ self.assertNotAlmostEqual(first, second,
+ delta=datetime.timedelta(seconds=5))
def test_assertRaises(self):
def _raise(e):
@@ -68,6 +92,16 @@ class Test_Assertions(unittest.TestCase):
else:
self.fail("assertRaises() didn't let exception pass through")
+ def testAssertNotRegexpMatches(self):
+ self.assertNotRegexpMatches('Ala ma kota', r'r+')
+ try:
+ self.assertNotRegexpMatches('Ala ma kota', r'k.t', 'Message')
+ except self.failureException as e:
+ self.assertIn("'kot'", e.args[0])
+ self.assertIn('Message', e.args[0])
+ else:
+ self.fail('assertNotRegexpMatches should have failed.')
+
class TestLongMessage(unittest.TestCase):
"""Test that the individual asserts honour longMessage.
diff --git a/Lib/unittest/test/test_break.py b/Lib/unittest/test/test_break.py
index a1a1eda..e3fae34 100644
--- a/Lib/unittest/test/test_break.py
+++ b/Lib/unittest/test/test_break.py
@@ -203,8 +203,9 @@ class TestBreak(unittest.TestCase):
p = Program(False)
p.runTests()
- self.assertEqual(FakeRunner.initArgs, [((), {'verbosity': verbosity,
- 'failfast': failfast})])
+ self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
+ 'verbosity': verbosity,
+ 'failfast': failfast})])
self.assertEqual(FakeRunner.runArgs, [test])
self.assertEqual(p.result, result)
@@ -215,8 +216,9 @@ class TestBreak(unittest.TestCase):
p = Program(True)
p.runTests()
- self.assertEqual(FakeRunner.initArgs, [((), {'verbosity': verbosity,
- 'failfast': failfast})])
+ self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None,
+ 'verbosity': verbosity,
+ 'failfast': failfast})])
self.assertEqual(FakeRunner.runArgs, [test])
self.assertEqual(p.result, result)
diff --git a/Lib/unittest/test/test_discovery.py b/Lib/unittest/test/test_discovery.py
index 5986271..1b0f08b 100644
--- a/Lib/unittest/test/test_discovery.py
+++ b/Lib/unittest/test/test_discovery.py
@@ -128,6 +128,7 @@ class TestDiscovery(unittest.TestCase):
loader = unittest.TestLoader()
original_isfile = os.path.isfile
+ original_isdir = os.path.isdir
def restore_isfile():
os.path.isfile = original_isfile
@@ -147,6 +148,12 @@ class TestDiscovery(unittest.TestCase):
self.assertIn(full_path, sys.path)
os.path.isfile = lambda path: True
+ os.path.isdir = lambda path: True
+
+ def restore_isdir():
+ os.path.isdir = original_isdir
+ self.addCleanup(restore_isdir)
+
_find_tests_args = []
def _find_tests(start_dir, pattern):
_find_tests_args.append((start_dir, pattern))
@@ -156,8 +163,8 @@ class TestDiscovery(unittest.TestCase):
suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar')
- top_level_dir = os.path.abspath(os.path.normpath('/foo/bar'))
- start_dir = os.path.abspath(os.path.normpath('/foo/bar/baz'))
+ top_level_dir = os.path.abspath('/foo/bar')
+ start_dir = os.path.abspath('/foo/bar/baz')
self.assertEqual(suite, "['tests']")
self.assertEqual(loader._top_level_dir, top_level_dir)
self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
diff --git a/Lib/unittest/test/test_loader.py b/Lib/unittest/test/test_loader.py
index 373ace9..7def474 100644
--- a/Lib/unittest/test/test_loader.py
+++ b/Lib/unittest/test/test_loader.py
@@ -524,12 +524,8 @@ class Test_TestLoader(unittest.TestCase):
# We're going to try to load this module as a side-effect, so it
# better not be loaded before we try.
#
- # Why pick audioop? Google shows it isn't used very often, so there's
- # a good chance that it won't be imported when this test is run
- module_name = 'audioop'
-
- if module_name in sys.modules:
- del sys.modules[module_name]
+ module_name = 'unittest.test.dummy'
+ sys.modules.pop(module_name, None)
loader = unittest.TestLoader()
try:
@@ -538,7 +534,7 @@ class Test_TestLoader(unittest.TestCase):
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [])
- # audioop should now be loaded, thanks to loadTestsFromName()
+ # module should now be loaded, thanks to loadTestsFromName()
self.assertIn(module_name, sys.modules)
finally:
if module_name in sys.modules:
@@ -911,12 +907,8 @@ class Test_TestLoader(unittest.TestCase):
# We're going to try to load this module as a side-effect, so it
# better not be loaded before we try.
#
- # Why pick audioop? Google shows it isn't used very often, so there's
- # a good chance that it won't be imported when this test is run
- module_name = 'audioop'
-
- if module_name in sys.modules:
- del sys.modules[module_name]
+ module_name = 'unittest.test.dummy'
+ sys.modules.pop(module_name, None)
loader = unittest.TestLoader()
try:
@@ -925,7 +917,7 @@ class Test_TestLoader(unittest.TestCase):
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [unittest.TestSuite()])
- # audioop should now be loaded, thanks to loadTestsFromName()
+ # module should now be loaded, thanks to loadTestsFromName()
self.assertIn(module_name, sys.modules)
finally:
if module_name in sys.modules:
diff --git a/Lib/unittest/test/test_result.py b/Lib/unittest/test/test_result.py
index 967b662..c703032 100644
--- a/Lib/unittest/test/test_result.py
+++ b/Lib/unittest/test/test_result.py
@@ -1,6 +1,6 @@
import io
import sys
-import warnings
+import textwrap
from test import support
@@ -25,6 +25,8 @@ class Test_TestResult(unittest.TestCase):
self.assertEqual(len(result.failures), 0)
self.assertEqual(result.testsRun, 0)
self.assertEqual(result.shouldStop, False)
+ self.assertIsNone(result._stdout_buffer)
+ self.assertIsNone(result._stderr_buffer)
# "This method can be called to signal that the set of tests being
# run should be aborted by setting the TestResult's shouldStop
@@ -302,6 +304,8 @@ def __init__(self, stream=None, descriptions=None, verbosity=None):
self.errors = []
self.testsRun = 0
self.shouldStop = False
+ self.buffer = False
+
classDict['__init__'] = __init__
OldResult = type('OldResult', (object,), classDict)
@@ -355,3 +359,129 @@ class Test_OldTestResult(unittest.TestCase):
# This will raise an exception if TextTestRunner can't handle old
# test result objects
runner.run(Test('testFoo'))
+
+
+class TestOutputBuffering(unittest.TestCase):
+
+ def setUp(self):
+ self._real_out = sys.stdout
+ self._real_err = sys.stderr
+
+ def tearDown(self):
+ sys.stdout = self._real_out
+ sys.stderr = self._real_err
+
+ def testBufferOutputOff(self):
+ real_out = self._real_out
+ real_err = self._real_err
+
+ result = unittest.TestResult()
+ self.assertFalse(result.buffer)
+
+ self.assertIs(real_out, sys.stdout)
+ self.assertIs(real_err, sys.stderr)
+
+ result.startTest(self)
+
+ self.assertIs(real_out, sys.stdout)
+ self.assertIs(real_err, sys.stderr)
+
+ def testBufferOutputStartTestAddSuccess(self):
+ real_out = self._real_out
+ real_err = self._real_err
+
+ result = unittest.TestResult()
+ self.assertFalse(result.buffer)
+
+ result.buffer = True
+
+ self.assertIs(real_out, sys.stdout)
+ self.assertIs(real_err, sys.stderr)
+
+ result.startTest(self)
+
+ self.assertIsNot(real_out, sys.stdout)
+ self.assertIsNot(real_err, sys.stderr)
+ self.assertIsInstance(sys.stdout, io.StringIO)
+ self.assertIsInstance(sys.stderr, io.StringIO)
+ self.assertIsNot(sys.stdout, sys.stderr)
+
+ out_stream = sys.stdout
+ err_stream = sys.stderr
+
+ result._original_stdout = io.StringIO()
+ result._original_stderr = io.StringIO()
+
+ print('foo')
+ print('bar', file=sys.stderr)
+
+ self.assertEqual(out_stream.getvalue(), 'foo\n')
+ self.assertEqual(err_stream.getvalue(), 'bar\n')
+
+ self.assertEqual(result._original_stdout.getvalue(), '')
+ self.assertEqual(result._original_stderr.getvalue(), '')
+
+ result.addSuccess(self)
+ result.stopTest(self)
+
+ self.assertIs(sys.stdout, result._original_stdout)
+ self.assertIs(sys.stderr, result._original_stderr)
+
+ self.assertEqual(result._original_stdout.getvalue(), '')
+ self.assertEqual(result._original_stderr.getvalue(), '')
+
+ self.assertEqual(out_stream.getvalue(), '')
+ self.assertEqual(err_stream.getvalue(), '')
+
+
+ def getStartedResult(self):
+ result = unittest.TestResult()
+ result.buffer = True
+ result.startTest(self)
+ return result
+
+ def testBufferOutputAddErrorOrFailure(self):
+ for message_attr, add_attr, include_error in [
+ ('errors', 'addError', True),
+ ('failures', 'addFailure', False),
+ ('errors', 'addError', True),
+ ('failures', 'addFailure', False)
+ ]:
+ result = self.getStartedResult()
+ buffered_out = sys.stdout
+ buffered_err = sys.stderr
+ result._original_stdout = io.StringIO()
+ result._original_stderr = io.StringIO()
+
+ print('foo', file=sys.stdout)
+ if include_error:
+ print('bar', file=sys.stderr)
+
+
+ addFunction = getattr(result, add_attr)
+ addFunction(self, (None, None, None))
+ result.stopTest(self)
+
+ result_list = getattr(result, message_attr)
+ self.assertEqual(len(result_list), 1)
+
+ test, message = result_list[0]
+ expectedOutMessage = textwrap.dedent("""
+ Stdout:
+ foo
+ """)
+ expectedErrMessage = ''
+ if include_error:
+ expectedErrMessage = textwrap.dedent("""
+ Stderr:
+ bar
+ """)
+ expectedFullMessage = 'NoneType\n%s%s' % (expectedOutMessage, expectedErrMessage)
+
+ self.assertIs(test, self)
+ self.assertEqual(result._original_stdout.getvalue(), expectedOutMessage)
+ self.assertEqual(result._original_stderr.getvalue(), expectedErrMessage)
+ self.assertMultiLineEqual(message, expectedFullMessage)
+
+if __name__ == '__main__':
+ unittest.main()