[Python-checkins] r79965 - in python/branches/py3k: Doc/library/unittest.rst Lib/test/regrtest.py Lib/test/test_argparse.py Lib/unittest/case.py Lib/unittest/loader.py Lib/unittest/main.py Lib/unittest/result.py Lib/unittest/runner.py Lib/unittes
Michael Foord
fuzzyman at gmail.com
Sun Apr 25 19:36:37 CEST 2010
So the use of "chain" in unittest.TestResult._exc_info_to_string is how you
got round the problem of the tests depending on calling
traceback.format_exception with (None, None, None)?
Do you still want me to fix this? Your workaround seems to be fine. :-)
All the best,
Michael
On 11 April 2010 21:43, benjamin.peterson <python-checkins at python.org>wrote:
> Author: benjamin.peterson
> Date: Sun Apr 11 22:43:16 2010
> New Revision: 79965
>
> Log:
> 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
> ........
>
>
> Added:
> python/branches/py3k/Lib/unittest/test/dummy.py
> - copied unchanged from r79464,
> /python/trunk/Lib/unittest/test/dummy.py
> Modified:
> python/branches/py3k/ (props changed)
> python/branches/py3k/Doc/library/unittest.rst
> python/branches/py3k/Lib/test/regrtest.py
> python/branches/py3k/Lib/test/test_argparse.py
> python/branches/py3k/Lib/unittest/case.py
> python/branches/py3k/Lib/unittest/loader.py
> python/branches/py3k/Lib/unittest/main.py
> python/branches/py3k/Lib/unittest/result.py
> python/branches/py3k/Lib/unittest/runner.py
> python/branches/py3k/Lib/unittest/test/test_assertions.py
> python/branches/py3k/Lib/unittest/test/test_break.py
> python/branches/py3k/Lib/unittest/test/test_discovery.py
> python/branches/py3k/Lib/unittest/test/test_loader.py
> python/branches/py3k/Lib/unittest/test/test_result.py
>
> Modified: python/branches/py3k/Doc/library/unittest.rst
>
> ==============================================================================
> --- python/branches/py3k/Doc/library/unittest.rst (original)
> +++ python/branches/py3k/Doc/library/unittest.rst Sun Apr 11 22:43:16
> 2010
> @@ -74,6 +74,11 @@
> Module :mod:`doctest`
> Another test-support module with a very different flavor.
>
> + `unittest2: A backport of new unittest features for Python 2.4-2.6 <
> http://pypi.python.org/pypi/unittest2>`_
> + Many new features were added to unittest in Python 2.7, including
> test
> + discovery. unittest2 allows you to use these features with earlier
> + versions of Python.
> +
> `Simple Smalltalk Testing: With Patterns <
> http://www.XProgramming.com/testfram.htm>`_
> Kent Beck's original paper on testing frameworks using the pattern
> shared
> by :mod:`unittest`.
> @@ -82,41 +87,13 @@
> Third-party unittest frameworks with a lighter-weight syntax for
> writing
> tests. For example, ``assert func(10) == 42``.
>
> - `python-mock <http://python-mock.sourceforge.net/>`_ and `minimock <
> http://blog.ianbicking.org/minimock.html>`_
> - Tools for creating mock test objects (objects simulating external
> - resources).
> -
> -
> -.. _unittest-command-line-interface:
> -
> -Command Line Interface
> -----------------------
> -
> -The unittest module can be used from the command line to run tests from
> -modules, classes or even individual test methods::
> -
> - python -m unittest test_module1 test_module2
> - python -m unittest test_module.TestClass
> - python -m unittest test_module.TestClass.test_method
> -
> -You can pass in a list with any combination of module names, and fully
> -qualified class or method names.
> -
> -You can run tests with more detail (higher verbosity) by passing in the -v
> flag::
> -
> - python -m unittest -v test_module
> -
> -For a list of all the command line options::
> -
> - python -m unittest -h
> -
> -.. versionchanged:: 3.2
> - In earlier versions it was only possible to run individual test methods
> and
> - not modules or classes.
> -
> -The command line can also be used for test discovery, for running all of
> the
> -tests in a project or just a subset.
> -
> + `The Python Testing Tools Taxonomy <
> http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy>`_
> + An extensive list of Python testing tools including functional
> testing
> + frameworks and mock object libraries.
> +
> + `Testing in Python Mailing List <
> http://lists.idyll.org/listinfo/testing-in-python>`_
> + A special-interest-group for discussion of testing, and testing
> tools,
> + in Python.
>
> .. _unittest-test-discovery:
>
> @@ -243,6 +220,100 @@
> are sufficient to meet many everyday testing needs. The remainder of the
> documentation explores the full feature set from first principles.
>
> +
> +.. _unittest-command-line-interface:
> +
> +Command Line Interface
> +----------------------
> +
> +The unittest module can be used from the command line to run tests from
> +modules, classes or even individual test methods::
> +
> + python -m unittest test_module1 test_module2
> + python -m unittest test_module.TestClass
> + python -m unittest test_module.TestClass.test_method
> +
> +You can pass in a list with any combination of module names, and fully
> +qualified class or method names.
> +
> +You can run tests with more detail (higher verbosity) by passing in the -v
> flag::
> +
> + python -m unittest -v test_module
> +
> +For a list of all the command line options::
> +
> + python -m unittest -h
> +
> +.. versionchanged:: 3.2
> + In earlier versions it was only possible to run individual test methods
> and
> + not modules or classes.
> +
> +
> +failfast, catch and buffer command line options
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +unittest supports three command options.
> +
> +* -f / --failfast
> +
> + Stop the test run on the first error or failure.
> +
> +* -c / --catch
> +
> + Control-c during the test run waits for the current test to end and then
> + reports all the results so far. A second control-c raises the normal
> + ``KeyboardInterrupt`` exception.
> +
> + See `Signal Handling`_ for the functions that provide this
> functionality.
> +
> +* -b / --buffer
> +
> + The standard out and standard error streams are buffered during the test
> + run. Output during a passing test is discarded. Output is echoed
> normally
> + on test fail or error and is added to the failure messages.
> +
> +.. versionadded:: 2.7
> + The command line options ``-c``, ``-b`` and ``-f`` where added.
> +
> +The command line can also be used for test discovery, for running all of
> the
> +tests in a project or just a subset.
> +
> +
> +.. _unittest-test-discovery:
> +
> +Test Discovery
> +--------------
> +
> +.. versionadded:: 2.7
> +
> +Unittest supports simple test discovery. For a project's tests to be
> +compatible with test discovery they must all be importable from the top
> level
> +directory of the project (in other words, they must all be in Python
> packages).
> +
> +Test discovery is implemented in :meth:`TestLoader.discover`, but can also
> be
> +used from the command line. The basic command line usage is::
> +
> + cd project_directory
> + python -m unittest discover
> +
> +The ``discover`` sub-command has the following options:
> +
> + -v, --verbose Verbose output
> + -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)
> +
> +The -s, -p, & -t options can be passsed in as positional arguments. The
> +following two command lines are equivalent::
> +
> + python -m unittest discover -s project_directory -p '*_test.py'
> + python -m unittest discover project_directory '*_test.py'
> +
> +Test modules and packages can customize test loading and discovery by
> through
> +the `load_tests protocol`_.
> +
> +
> .. _organizing-tests:
>
> Organizing test code
> @@ -580,6 +651,9 @@
> Mark the test as an expected failure. If the test fails when run, the
> test
> is not counted as a failure.
>
> +Skipped tests will not have :meth:`setUp` or :meth:`tearDown` run around
> them.
> +Skipped classes will not have :meth:`setUpClass` or :meth:`tearDownClass`
> run.
> +
>
> .. _unittest-contents:
>
> @@ -645,6 +719,36 @@
> the outcome of the test method. The default implementation does
> nothing.
>
>
> + .. method:: setUpClass()
> +
> + A class method called before tests in an individual class run.
> + ``setUpClass`` is called with the class as the only argument
> + and must be decorated as a :func:`classmethod`::
> +
> + @classmethod
> + def setUpClass(cls):
> + ...
> +
> + See `Class and Module Fixtures`_ for more details.
> +
> + .. versionadded:: 3.2
> +
> +
> + .. method:: tearDownClass()
> +
> + A class method called after tests in an individual class have run.
> + ``tearDownClass`` is called with the class as the only argument
> + and must be decorated as a :meth:`classmethod`::
> +
> + @classmethod
> + def tearDownClass(cls):
> + ...
> +
> + See `Class and Module Fixtures`_ for more details.
> +
> + .. versionadded:: 3.2
> +
> +
> .. method:: run(result=None)
>
> Run the test, collecting the result into the test result object
> passed as
> @@ -727,8 +831,8 @@
> :meth:`failIfEqual`; use :meth:`assertNotEqual`.
>
>
> - .. method:: assertAlmostEqual(first, second, *, places=7, msg=None)
> - failUnlessAlmostEqual(first, second, *, places=7, msg=None)
> + .. method:: assertAlmostEqual(first, second, *, places=7, msg=None,
> delta=None)
> + failUnlessAlmostEqual(first, second, *, places=7, msg=None,
> delta=None)
>
> Test that *first* and *second* are approximately equal by computing
> the
> difference, rounding to the given number of decimal *places* (default
> 7),
> @@ -741,13 +845,14 @@
>
> .. versionchanged:: 3.2
> Objects that compare equal are automatically almost equal.
> + Added the ``delta`` keyword argument.
>
> .. deprecated:: 3.1
> :meth:`failUnlessAlmostEqual`; use :meth:`assertAlmostEqual`.
>
>
> - .. method:: assertNotAlmostEqual(first, second, *, places=7, msg=None)
> - failIfAlmostEqual(first, second, *, places=7, msg=None)
> + .. method:: assertNotAlmostEqual(first, second, *, places=7, msg=None,
> delta=None)
> + failIfAlmostEqual(first, second, *, places=7, msg=None,
> delta=None)
>
> Test that *first* and *second* are not approximately equal by
> computing
> the difference, rounding to the given number of decimal *places*
> (default
> @@ -758,8 +863,14 @@
> compare equal, the test will fail with the explanation given by
> *msg*, or
> :const:`None`.
>
> + If *delta* is supplied instead of *places* then the the difference
> + between *first* and *second* must be more than *delta*.
> +
> + Supplying both *delta* and *places* raises a ``TypeError``.
> +
> .. versionchanged:: 3.2
> Objects that compare equal automatically fail.
> + Added the ``delta`` keyword argument.
>
> .. deprecated:: 3.1
> :meth:`failIfAlmostEqual`; use :meth:`assertNotAlmostEqual`.
> @@ -802,6 +913,16 @@
> .. versionadded:: 3.1
>
>
> + .. method:: assertNotRegexpMatches(text, regexp, msg=None)
> +
> + Verifies that a *regexp* search does not match *text*. Fails with
> an error
> + message including the pattern and the *text*. *regexp* may be
> + a regular expression object or a string containing a regular
> expression
> + suitable for use by :func:`re.search`.
> +
> + .. versionadded:: 2.7
> +
> +
> .. method:: assertIn(first, second, msg=None)
> assertNotIn(first, second, msg=None)
>
> @@ -1342,6 +1463,8 @@
> ``load_tests`` does not need to pass this argument in to
> ``loader.discover()``.
>
> + *start_dir* can be a dotted module name as well as a directory.
> +
> .. versionadded:: 3.2
>
>
> @@ -1433,6 +1556,24 @@
> The total number of tests run so far.
>
>
> + .. attribute:: buffer
> +
> + If set to true, ``sys.stdout`` and ``sys.stderr`` will be buffered
> in between
> + :meth:`startTest` and :meth:`stopTest` being called. Collected
> output will
> + only be echoed onto the real ``sys.stdout`` and ``sys.stderr`` if
> the test
> + fails or errors. Any output is also attached to the failure / error
> message.
> +
> + .. versionadded:: 2.7
> +
> +
> + .. attribute:: failfast
> +
> + If set to true :meth:`stop` will be called on the first failure or
> error,
> + halting the test run.
> +
> + .. versionadded:: 2.7
> +
> +
> .. method:: wasSuccessful()
>
> Return :const:`True` if all tests run so far have passed, otherwise
> returns
> @@ -1461,18 +1602,11 @@
>
> Called when the test case *test* is about to be run.
>
> - The default implementation simply increments the instance's
> :attr:`testsRun`
> - counter.
> -
> -
> .. method:: stopTest(test)
>
> Called after the test case *test* has been executed, regardless of
> the
> outcome.
>
> - The default implementation does nothing.
> -
> -
> .. method:: startTestRun(test)
>
> Called once before any tests are executed.
> @@ -1572,12 +1706,12 @@
>
> ``_makeResult()`` instantiates the class or callable passed in the
> ``TextTestRunner`` constructor as the ``resultclass`` argument. It
> - defaults to :class::`TextTestResult` if no ``resultclass`` is
> provided.
> + defaults to :class:`TextTestResult` if no ``resultclass`` is
> provided.
> The result class is instantiated with the following arguments::
>
> stream, descriptions, verbosity
>
> -.. function:: main(module='__main__', defaultTest=None, argv=None,
> testRunner=None, testLoader=unittest.loader.defaultTestLoader, exit=True,
> verbosity=1)
> +.. function:: main(module='__main__', defaultTest=None, argv=None,
> testRunner=None, testLoader=unittest.loader.defaultTestLoader, exit=True,
> verbosity=1, failfast=None, catchbreak=None, buffer=None)
>
> A command-line program that runs a set of tests; this is primarily for
> making
> test modules conveniently executable. The simplest use for this
> function is to
> @@ -1603,11 +1737,15 @@
> >>> from unittest import main
> >>> main(module='test_module', exit=False)
>
> + The ``failfast``, ``catchbreak`` and ``buffer`` parameters have the
> same
> + effect as the `failfast, catch and buffer command line options`_.
> +
> Calling ``main`` actually returns an instance of the ``TestProgram``
> class.
> This stores the result of the tests run as the ``result`` attribute.
>
> .. versionchanged:: 3.2
> - The ``exit`` and ``verbosity`` parameters were added.
> + The ``exit``, ``verbosity``, ``failfast``, ``catchbreak`` and
> ``buffer``
> + parameters were added.
>
>
> load_tests Protocol
> @@ -1677,3 +1815,113 @@
> package_tests = loader.discover(start_dir=this_dir,
> pattern=pattern)
> standard_tests.addTests(package_tests)
> return standard_tests
> +
> +
> +Class and Module Fixtures
> +-------------------------
> +
> +Class and module level fixtures are implemented in :class:`TestSuite`.
> When
> +the test suite encounters a test from a new class then
> :meth:`tearDownClass`
> +from the previous class (if there is one) is called, followed by
> +:meth:`setUpClass` from the new class.
> +
> +Similarly if a test is from a different module from the previous test then
> +``tearDownModule`` from the previous module is run, followed by
> +``setUpModule`` from the new module.
> +
> +After all the tests have run the final ``tearDownClass`` and
> +``tearDownModule`` are run.
> +
> +Note that shared fixtures do not play well with [potential] features like
> test
> +parallelization and they break test isolation. They should be used with
> care.
> +
> +The default ordering of tests created by the unittest test loaders is to
> group
> +all tests from the same modules and classes together. This will lead to
> +``setUpClass`` / ``setUpModule`` (etc) being called exactly once per class
> and
> +module. If you randomize the order, so that tests from different modules
> and
> +classes are adjacent to each other, then these shared fixture functions
> may be
> +called multiple times in a single test run.
> +
> +Shared fixtures are not intended to work with suites with non-standard
> +ordering. A ``BaseTestSuite`` still exists for frameworks that don't want
> to
> +support shared fixtures.
> +
> +If there are any exceptions raised during one of the shared fixture
> functions
> +the test is reported as an error. Because there is no corresponding test
> +instance an ``_ErrorHolder`` object (that has the same interface as a
> +:class:`TestCase`) is created to represent the error. If you are just
> using
> +the standard unittest test runner then this detail doesn't matter, but if
> you
> +are a framework author it may be relevant.
> +
> +
> +setUpClass and tearDownClass
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +These must be implemented as class methods::
> +
> + import unittest
> +
> + class Test(unittest.TestCase):
> + @classmethod
> + def setUpClass(cls):
> + cls._connection = createExpensiveConnectionObject()
> +
> + @classmethod
> + def tearDownClass(cls):
> + cls._connection.destroy()
> +
> +If you want the ``setUpClass`` and ``tearDownClass`` on base classes
> called
> +then you must call up to them yourself. The implementations in
> +:class:`TestCase` are empty.
> +
> +If an exception is raised during a ``setUpClass`` then the tests in the
> class
> +are not run and the ``tearDownClass`` is not run. Skipped classes will not
> +have ``setUpClass`` or ``tearDownClass`` run.
> +
> +
> +setUpModule and tearDownModule
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +These should be implemented as functions::
> +
> + def setUpModule():
> + createConnection()
> +
> + def tearDownModule():
> + closeConnection()
> +
> +If an exception is raised in a ``setUpModule`` then none of the tests in
> the
> +module will be run and the ``tearDownModule`` will not be run.
> +
> +
> +Signal Handling
> +---------------
> +
> +The -c / --catch command line option to unittest, along with the
> ``catchbreak``
> +parameter to :func:`unittest.main()`, provide more friendly handling of
> +control-c during a test run. With catch break behavior enabled control-c
> will
> +allow the currently running test to complete, and the test run will then
> end
> +and report all the results so far. A second control-c will raise a
> +``KeyboardInterrupt`` in the usual way.
> +
> +There are a few utility functions for framework authors to enable this
> +functionality within test frameworks.
> +
> +.. function:: installHandler()
> +
> + Install the control-c handler. When a :const:`signal.SIGINT` is
> received
> + (usually in response to the user pressing control-c) all registered
> results
> + have :meth:`~TestResult.stop` called.
> +
> +.. function:: registerResult(result)
> +
> + Register a :class:`TestResult` object for control-c handling.
> Registering a
> + result stores a weak reference to it, so it doesn't prevent the result
> from
> + being garbage collected.
> +
> +.. function:: removeResult(result)
> +
> + Remove a registered result. Once a result has been removed then
> + :meth:`~TestResult.stop` will no longer be called on that result object
> in
> + response to a control-c.
> +
>
> Modified: python/branches/py3k/Lib/test/regrtest.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/test/regrtest.py (original)
> +++ python/branches/py3k/Lib/test/regrtest.py Sun Apr 11 22:43:16 2010
> @@ -880,6 +880,10 @@
> 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.
>
> Modified: python/branches/py3k/Lib/test/test_argparse.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/test/test_argparse.py (original)
> +++ python/branches/py3k/Lib/test/test_argparse.py Sun Apr 11 22:43:16
> 2010
> @@ -12,6 +12,8 @@
> from io import StringIO
>
> from test import support
> +class StdIOBuffer(StringIO):
> + pass
>
> class TestCase(unittest.TestCase):
>
> @@ -25,6 +27,7 @@
> super(TestCase, self).assertEqual(obj1, obj2)
>
>
> +
> class TempDirMixin(object):
>
> def setUp(self):
> @@ -81,15 +84,15 @@
> # 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 @@
> 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 @@
> 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)
>
> Modified: python/branches/py3k/Lib/unittest/case.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/case.py (original)
> +++ python/branches/py3k/Lib/unittest/case.py Sun Apr 11 22:43:16 2010
> @@ -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.
>
> Modified: python/branches/py3k/Lib/unittest/loader.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/loader.py (original)
> +++ python/branches/py3k/Lib/unittest/loader.py Sun Apr 11 22:43:16 2010
> @@ -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]
>
>
> Modified: python/branches/py3k/Lib/unittest/main.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/main.py (original)
> +++ python/branches/py3k/Lib/unittest/main.py Sun Apr 11 22:43:16 2010
> @@ -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
>
> Modified: python/branches/py3k/Lib/unittest/result.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/result.py (original)
> +++ python/branches/py3k/Lib/unittest/result.py Sun Apr 11 22:43:16 2010
> @@ -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
>
> Modified: python/branches/py3k/Lib/unittest/runner.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/runner.py (original)
> +++ python/branches/py3k/Lib/unittest/runner.py Sun Apr 11 22:43:16 2010
> @@ -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:
>
> Modified: python/branches/py3k/Lib/unittest/test/test_assertions.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/test/test_assertions.py (original)
> +++ python/branches/py3k/Lib/unittest/test/test_assertions.py Sun Apr 11
> 22:43:16 2010
> @@ -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.
>
> Modified: python/branches/py3k/Lib/unittest/test/test_break.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/test/test_break.py (original)
> +++ python/branches/py3k/Lib/unittest/test/test_break.py Sun Apr 11
> 22:43:16 2010
> @@ -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)
>
>
> Modified: python/branches/py3k/Lib/unittest/test/test_discovery.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/test/test_discovery.py (original)
> +++ python/branches/py3k/Lib/unittest/test/test_discovery.py Sun Apr 11
> 22:43:16 2010
> @@ -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')])
>
> Modified: python/branches/py3k/Lib/unittest/test/test_loader.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/test/test_loader.py (original)
> +++ python/branches/py3k/Lib/unittest/test/test_loader.py Sun Apr 11
> 22:43:16 2010
> @@ -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:
>
> Modified: python/branches/py3k/Lib/unittest/test/test_result.py
>
> ==============================================================================
> --- python/branches/py3k/Lib/unittest/test/test_result.py (original)
> +++ python/branches/py3k/Lib/unittest/test/test_result.py Sun Apr 11
> 22:43:16 2010
> @@ -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()
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> http://mail.python.org/mailman/listinfo/python-checkins
>
--
http://www.ironpythoninaction.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-checkins/attachments/20100425/c0eacebf/attachment-0001.html>
More information about the Python-checkins
mailing list