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
........
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 @@
                                                           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 @@
            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 @@
             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 @@
         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 @@
 
 __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 @@
   -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 @@
 
 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 @@
   -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 @@
     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 @@
         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 @@
     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 @@
             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 @@
                     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 @@
             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 @@
             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 @@
         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 @@
         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 @@
         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 @@
     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 @@
 
     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 @@
         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 @@
         # 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..f13d623 100644
--- a/Lib/unittest/runner.py
+++ b/Lib/unittest/runner.py
@@ -125,11 +125,12 @@
     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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
 
         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 @@
         # 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 @@
             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 @@
         # 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 @@
             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 @@
         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 @@
     self.errors = []
     self.testsRun = 0
     self.shouldStop = False
+    self.buffer = False
+
 classDict['__init__'] = __init__
 OldResult = type('OldResult', (object,), classDict)
 
@@ -355,3 +359,129 @@
         # 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()