[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