summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2009-05-08 20:42:26 (GMT)
committerBenjamin Peterson <benjamin@python.org>2009-05-08 20:42:26 (GMT)
commit25c95f12987c08f446f355db6b9a807f3dea76a0 (patch)
tree9d70b6e22b45cec0e40cc6d5d174d03012af7f50 /Lib/test
parent8a282d175b5a9f1cd48c5de506fb02d60b20d6d5 (diff)
downloadcpython-25c95f12987c08f446f355db6b9a807f3dea76a0.zip
cpython-25c95f12987c08f446f355db6b9a807f3dea76a0.tar.gz
cpython-25c95f12987c08f446f355db6b9a807f3dea76a0.tar.bz2
Merged revisions 70768,71657,71721,71729,71794,71976,72036-72037,72079,72085,72131-72134,72191,72197-72198,72219,72221,72225,72303,72434,72467,72476 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r70768 | andrew.kuchling | 2009-03-30 17:29:15 -0500 (Mon, 30 Mar 2009) | 1 line Typo fixes ........ r71657 | vinay.sajip | 2009-04-16 14:07:37 -0500 (Thu, 16 Apr 2009) | 1 line Issue #5768: Change to Unicode output logic and test case for same. ........ r71721 | benjamin.peterson | 2009-04-18 14:26:19 -0500 (Sat, 18 Apr 2009) | 1 line fix a few nits in unittest.py #5771 ........ r71729 | benjamin.peterson | 2009-04-18 16:03:10 -0500 (Sat, 18 Apr 2009) | 1 line move test to a more appropiate one ........ r71794 | vinay.sajip | 2009-04-22 07:10:47 -0500 (Wed, 22 Apr 2009) | 2 lines Issue #5170: Fixed regression caused when fixing #5768. ........ r71976 | mark.dickinson | 2009-04-26 14:54:55 -0500 (Sun, 26 Apr 2009) | 2 lines Fix typo in function name ........ r72036 | georg.brandl | 2009-04-27 12:04:23 -0500 (Mon, 27 Apr 2009) | 1 line #5848: small unittest doc patch. ........ r72037 | georg.brandl | 2009-04-27 12:09:53 -0500 (Mon, 27 Apr 2009) | 1 line #5840: dont claim we dont support TLS. ........ r72079 | r.david.murray | 2009-04-28 14:02:55 -0500 (Tue, 28 Apr 2009) | 2 lines Remove spurious 'u'. ........ r72085 | georg.brandl | 2009-04-28 16:48:35 -0500 (Tue, 28 Apr 2009) | 1 line Make the doctests in the docs pass, except for those in the turtle module. ........ r72131 | benjamin.peterson | 2009-04-29 17:43:35 -0500 (Wed, 29 Apr 2009) | 1 line fix test_shutil on ZFS #5676 ........ r72132 | georg.brandl | 2009-04-29 17:44:07 -0500 (Wed, 29 Apr 2009) | 1 line #5878: fix repr of re object. ........ r72133 | benjamin.peterson | 2009-04-29 17:44:15 -0500 (Wed, 29 Apr 2009) | 1 line make sure mode is removable while cleaning up test droppings ........ r72134 | benjamin.peterson | 2009-04-29 19:06:33 -0500 (Wed, 29 Apr 2009) | 1 line make sure to close file ........ r72191 | michael.foord | 2009-05-02 06:43:06 -0500 (Sat, 02 May 2009) | 9 lines Adds an exit parameter to unittest.main(). If False main no longer calls sys.exit. Closes issue 3379. Michael Foord ........ r72197 | benjamin.peterson | 2009-05-02 11:24:37 -0500 (Sat, 02 May 2009) | 1 line don't let sys.argv be used in the tests ........ r72198 | andrew.kuchling | 2009-05-02 12:12:15 -0500 (Sat, 02 May 2009) | 1 line Add items ........ r72219 | michael.foord | 2009-05-02 15:15:05 -0500 (Sat, 02 May 2009) | 8 lines Add addCleanup and doCleanups to unittest.TestCase. Closes issue 5679. Michael Foord ........ r72221 | benjamin.peterson | 2009-05-02 15:26:53 -0500 (Sat, 02 May 2009) | 1 line add myself ........ r72225 | michael.foord | 2009-05-02 17:43:34 -0500 (Sat, 02 May 2009) | 1 line ........ r72303 | benjamin.peterson | 2009-05-04 19:55:24 -0500 (Mon, 04 May 2009) | 1 line using sys._getframe(x), where x > 0 doesnt' work on IronPython ........ r72434 | r.david.murray | 2009-05-07 13:09:58 -0500 (Thu, 07 May 2009) | 2 lines Pre-opened test file needs to be opened in binary mode. ........ r72467 | georg.brandl | 2009-05-08 07:17:34 -0500 (Fri, 08 May 2009) | 1 line Fix name. ........ r72476 | thomas.heller | 2009-05-08 15:09:40 -0500 (Fri, 08 May 2009) | 4 lines Add a file that contains diffs between offical libffi files and the files in this repository. Should make it easier to merge new libffi versions. ........
Diffstat (limited to 'Lib/test')
-rwxr-xr-xLib/test/regrtest.py5
-rw-r--r--Lib/test/test_aifc.py2
-rw-r--r--Lib/test/test_descr.py55
-rw-r--r--Lib/test/test_logging.py1
-rw-r--r--Lib/test/test_shutil.py18
-rw-r--r--Lib/test/test_unittest.py413
6 files changed, 427 insertions, 67 deletions
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 0408a02..673f11f 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -663,6 +663,7 @@ def runtest_inner(test, generate, verbose, quiet, test_times,
def cleanup_test_droppings(testname, verbose):
import shutil
+ import stat
# Try to clean up junk commonly left behind. While tests shouldn't leave
# any files or directories behind, when a test fails that can be tedious
@@ -687,6 +688,10 @@ def cleanup_test_droppings(testname, verbose):
if verbose:
print("%r left behind %s %r" % (testname, kind, name))
try:
+ # if we have chmod, fix possible permissions problems
+ # that might prevent cleanup
+ if (hasattr(os, 'chmod')):
+ os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
nuker(name)
except Exception as msg:
print(("%r left behind %s %r and it couldn't be "
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
index 0248615..4869bf3 100644
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -27,7 +27,7 @@ class AIFCTest(unittest.TestCase):
def test_skipunknown(self):
#Issue 2245
#This file contains chunk types aifc doesn't recognize.
- f = aifc.open(self.sndfilepath)
+ self.f = aifc.open(self.sndfilepath)
def test_params(self):
f = self.f = aifc.open(self.sndfilepath)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index ba0e0b8..37cab01 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3585,31 +3585,6 @@ order (MRO) for bases """
self.assertEqual(e.a, 2)
self.assertEqual(C2.__subclasses__(), [D])
- # stuff that shouldn't:
- class L(list):
- pass
-
- try:
- L.__bases__ = (dict,)
- except TypeError:
- pass
- else:
- self.fail("shouldn't turn list subclass into dict subclass")
-
- try:
- list.__bases__ = (dict,)
- except TypeError:
- pass
- else:
- self.fail("shouldn't be able to assign to list.__bases__")
-
- try:
- D.__bases__ = (C2, list)
- except TypeError:
- pass
- else:
- assert 0, "best_base calculation found wanting"
-
try:
del D.__bases__
except (TypeError, AttributeError):
@@ -3657,6 +3632,36 @@ order (MRO) for bases """
if tp is not object:
self.assertEqual(len(tp.__bases__), 1, tp)
+ class L(list):
+ pass
+
+ class C(object):
+ pass
+
+ class D(C):
+ pass
+
+ try:
+ L.__bases__ = (dict,)
+ except TypeError:
+ pass
+ else:
+ self.fail("shouldn't turn list subclass into dict subclass")
+
+ try:
+ list.__bases__ = (dict,)
+ except TypeError:
+ pass
+ else:
+ self.fail("shouldn't be able to assign to list.__bases__")
+
+ try:
+ D.__bases__ = (C, list)
+ except TypeError:
+ pass
+ else:
+ assert 0, "best_base calculation found wanting"
+
def test_mutable_bases_with_failing_mro(self):
# Testing mutable bases with failing mro...
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 1463cf7..69ec491 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -894,6 +894,7 @@ class EncodingTest(BaseTest):
message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
#Ensure it's written in a Cyrillic encoding
writer_class = codecs.getwriter('cp1251')
+ writer_class.encoding = 'cp1251'
stream = io.BytesIO()
writer = writer_class(stream, 'strict')
handler = logging.StreamHandler(writer)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index cdb039d..5a546ec 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -46,9 +46,23 @@ class TestShutil(unittest.TestCase):
shutil.rmtree(TESTFN)
def check_args_to_onerror(self, func, arg, exc):
+ # test_rmtree_errors deliberately runs rmtree
+ # on a directory that is chmod 400, which will fail.
+ # This function is run when shutil.rmtree fails.
+ # 99.9% of the time it initially fails to remove
+ # a file in the directory, so the first time through
+ # func is os.remove.
+ # However, some Linux machines running ZFS on
+ # FUSE experienced a failure earlier in the process
+ # at os.listdir. The first failure may legally
+ # be either.
if self.errorState == 0:
- self.assertEqual(func, os.remove)
- self.assertEqual(arg, self.childpath)
+ if func is os.remove:
+ self.assertEqual(arg, self.childpath)
+ else:
+ self.assertIs(func, os.listdir,
+ "func must be either os.remove or os.listdir")
+ self.assertEqual(arg, TESTFN)
self.failUnless(issubclass(exc[0], OSError))
self.errorState = 1
else:
diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py
index d0d2049..e7097cc 100644
--- a/Lib/test/test_unittest.py
+++ b/Lib/test/test_unittest.py
@@ -9,9 +9,10 @@ Still need testing:
import re
from test import support
import unittest
-from unittest import TestCase
+from unittest import TestCase, TestProgram
import types
from copy import deepcopy
+import io
### Support code
################################################################
@@ -25,10 +26,18 @@ class LoggingResult(unittest.TestResult):
self._events.append('startTest')
super().startTest(test)
+ def startTestRun(self):
+ self._events.append('startTestRun')
+ super(LoggingResult, self).startTestRun()
+
def stopTest(self, test):
self._events.append('stopTest')
super().stopTest(test)
+ def stopTestRun(self):
+ self._events.append('stopTestRun')
+ super(LoggingResult, self).stopTestRun()
+
def addFailure(self, *args):
self._events.append('addFailure')
super().addFailure(*args)
@@ -1826,6 +1835,12 @@ class Test_TestResult(TestCase):
self.assertEqual(result.testsRun, 1)
self.assertEqual(result.shouldStop, False)
+ # "Called before and after tests are run. The default implementation does nothing."
+ def test_startTestRun_stopTestRun(self):
+ result = unittest.TestResult()
+ result.startTestRun()
+ result.stopTestRun()
+
# "addSuccess(test)"
# ...
# "Called when the test case test succeeds"
@@ -1973,6 +1988,53 @@ class Foo(unittest.TestCase):
class Bar(Foo):
def test2(self): pass
+class LoggingTestCase(unittest.TestCase):
+ """A test case which logs its calls."""
+
+ def __init__(self, events):
+ super(LoggingTestCase, self).__init__('test')
+ self.events = events
+
+ def setUp(self):
+ self.events.append('setUp')
+
+ def test(self):
+ self.events.append('test')
+
+ def tearDown(self):
+ self.events.append('tearDown')
+
+class ResultWithNoStartTestRunStopTestRun(object):
+ """An object honouring TestResult before startTestRun/stopTestRun."""
+
+ def __init__(self):
+ self.failures = []
+ self.errors = []
+ self.testsRun = 0
+ self.skipped = []
+ self.expectedFailures = []
+ self.unexpectedSuccesses = []
+ self.shouldStop = False
+
+ def startTest(self, test):
+ pass
+
+ def stopTest(self, test):
+ pass
+
+ def addError(self, test):
+ pass
+
+ def addFailure(self, test):
+ pass
+
+ def addSuccess(self, test):
+ pass
+
+ def wasSuccessful(self):
+ return True
+
+
################################################################
### /Support code for Test_TestCase
@@ -2067,19 +2129,30 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
- class Foo(unittest.TestCase):
+ class Foo(LoggingTestCase):
def setUp(self):
- events.append('setUp')
+ super(Foo, self).setUp()
raise RuntimeError('raised by Foo.setUp')
- def test(self):
- events.append('test')
+ Foo(events).run(result)
+ expected = ['startTest', 'setUp', 'addError', 'stopTest']
+ self.assertEqual(events, expected)
- def tearDown(self):
- events.append('tearDown')
+ # "With a temporary result stopTestRun is called when setUp errors.
+ def test_run_call_order__error_in_setUp_default_result(self):
+ events = []
- Foo('test').run(result)
- expected = ['startTest', 'setUp', 'addError', 'stopTest']
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+
+ def setUp(self):
+ super(Foo, self).setUp()
+ raise RuntimeError('raised by Foo.setUp')
+
+ Foo(events).run()
+ expected = ['startTestRun', 'startTest', 'setUp', 'addError',
+ 'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
@@ -2093,20 +2166,32 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
+ class Foo(LoggingTestCase):
def test(self):
- events.append('test')
+ super(Foo, self).test()
raise RuntimeError('raised by Foo.test')
- def tearDown(self):
- events.append('tearDown')
-
expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown',
'stopTest']
- Foo('test').run(result)
+ Foo(events).run(result)
+ self.assertEqual(events, expected)
+
+ # "With a default result, an error in the test still results in stopTestRun
+ # being called."
+ def test_run_call_order__error_in_test_default_result(self):
+ events = []
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+
+ def test(self):
+ super(Foo, self).test()
+ raise RuntimeError('raised by Foo.test')
+
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError',
+ 'tearDown', 'stopTest', 'stopTestRun']
+ Foo(events).run()
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
@@ -2120,20 +2205,30 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
+ class Foo(LoggingTestCase):
def test(self):
- events.append('test')
+ super(Foo, self).test()
self.fail('raised by Foo.test')
- def tearDown(self):
- events.append('tearDown')
-
expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown',
'stopTest']
- Foo('test').run(result)
+ Foo(events).run(result)
+ self.assertEqual(events, expected)
+
+ # "When a test fails with a default result stopTestRun is still called."
+ def test_run_call_order__failure_in_test_default_result(self):
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+ def test(self):
+ super(Foo, self).test()
+ self.fail('raised by Foo.test')
+
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure',
+ 'tearDown', 'stopTest', 'stopTestRun']
+ events = []
+ Foo(events).run()
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
@@ -2147,22 +2242,44 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
- def test(self):
- events.append('test')
-
+ class Foo(LoggingTestCase):
def tearDown(self):
- events.append('tearDown')
+ super(Foo, self).tearDown()
raise RuntimeError('raised by Foo.tearDown')
- Foo('test').run(result)
+ Foo(events).run(result)
expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError',
'stopTest']
self.assertEqual(events, expected)
+ # "When tearDown errors with a default result stopTestRun is still called."
+ def test_run_call_order__error_in_tearDown_default_result(self):
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+ def tearDown(self):
+ super(Foo, self).tearDown()
+ raise RuntimeError('raised by Foo.tearDown')
+
+ events = []
+ Foo(events).run()
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'tearDown',
+ 'addError', 'stopTest', 'stopTestRun']
+ self.assertEqual(events, expected)
+
+ # "TestCase.run() still works when the defaultTestResult is a TestResult
+ # that does not support startTestRun and stopTestRun.
+ def test_run_call_order_default_result(self):
+
+ class Foo(unittest.TestCase):
+ def defaultTestResult(self):
+ return ResultWithNoStartTestRunStopTestRun()
+ def test(self):
+ pass
+
+ Foo('test').run()
+
# "This class attribute gives the exception raised by the test() method.
# If a test framework needs to use a specialized exception, possibly to
# carry additional information, it must subclass this exception in
@@ -2253,7 +2370,9 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
self.failUnless(isinstance(Foo().id(), str))
# "If result is omitted or None, a temporary result object is created
- # and used, but is not made available to the caller"
+ # and used, but is not made available to the caller. As TestCase owns the
+ # temporary result startTestRun and stopTestRun are called.
+
def test_run__uses_defaultTestResult(self):
events = []
@@ -2267,7 +2386,8 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
# Make run() find a result object on its own
Foo('test').run()
- expected = ['startTest', 'test', 'addSuccess', 'stopTest']
+ expected = ['startTestRun', 'startTest', 'test', 'addSuccess',
+ 'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
def testShortDescriptionWithoutDocstring(self):
@@ -3012,6 +3132,220 @@ class TestLongMessage(TestCase):
"^unexpectedly identical: None : oops$"])
+class TestCleanUp(TestCase):
+
+ def testCleanUp(self):
+ class TestableTest(TestCase):
+ def testNothing(self):
+ pass
+
+ test = TestableTest('testNothing')
+ self.assertEqual(test._cleanups, [])
+
+ cleanups = []
+
+ def cleanup1(*args, **kwargs):
+ cleanups.append((1, args, kwargs))
+
+ def cleanup2(*args, **kwargs):
+ cleanups.append((2, args, kwargs))
+
+ test.addCleanup(cleanup1, 1, 2, 3, four='hello', five='goodbye')
+ test.addCleanup(cleanup2)
+
+ self.assertEqual(test._cleanups,
+ [(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')),
+ (cleanup2, (), {})])
+
+ result = test.doCleanups()
+ self.assertTrue(result)
+
+ self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
+
+ def testCleanUpWithErrors(self):
+ class TestableTest(TestCase):
+ def testNothing(self):
+ pass
+
+ class MockResult(object):
+ errors = []
+ def addError(self, test, exc_info):
+ self.errors.append((test, exc_info))
+
+ result = MockResult()
+ test = TestableTest('testNothing')
+ test._result = result
+
+ exc1 = Exception('foo')
+ exc2 = Exception('bar')
+ def cleanup1():
+ raise exc1
+
+ def cleanup2():
+ raise exc2
+
+ test.addCleanup(cleanup1)
+ test.addCleanup(cleanup2)
+
+ self.assertFalse(test.doCleanups())
+
+ (test1, (Type1, instance1, _)), (test2, (Type2, instance2, _)) = reversed(MockResult.errors)
+ self.assertEqual((test1, Type1, instance1), (test, Exception, exc1))
+ self.assertEqual((test2, Type2, instance2), (test, Exception, exc2))
+
+ def testCleanupInRun(self):
+ blowUp = False
+ ordering = []
+
+ class TestableTest(TestCase):
+ def setUp(self):
+ ordering.append('setUp')
+ if blowUp:
+ raise Exception('foo')
+
+ def testNothing(self):
+ ordering.append('test')
+
+ def tearDown(self):
+ ordering.append('tearDown')
+
+ test = TestableTest('testNothing')
+
+ def cleanup1():
+ ordering.append('cleanup1')
+ def cleanup2():
+ ordering.append('cleanup2')
+ test.addCleanup(cleanup1)
+ test.addCleanup(cleanup2)
+
+ def success(some_test):
+ self.assertEqual(some_test, test)
+ ordering.append('success')
+
+ result = unittest.TestResult()
+ result.addSuccess = success
+
+ test.run(result)
+ self.assertEqual(ordering, ['setUp', 'test', 'tearDown',
+ 'cleanup2', 'cleanup1', 'success'])
+
+ blowUp = True
+ ordering = []
+ test = TestableTest('testNothing')
+ test.addCleanup(cleanup1)
+ test.run(result)
+ self.assertEqual(ordering, ['setUp', 'cleanup1'])
+
+
+class Test_TestProgram(TestCase):
+
+ # Horrible white box test
+ def testNoExit(self):
+ result = object()
+ test = object()
+
+ class FakeRunner(object):
+ def run(self, test):
+ self.test = test
+ return result
+
+ runner = FakeRunner()
+
+ try:
+ oldParseArgs = TestProgram.parseArgs
+ TestProgram.parseArgs = lambda *args: None
+ TestProgram.test = test
+
+ program = TestProgram(testRunner=runner, exit=False)
+
+ self.assertEqual(program.result, result)
+ self.assertEqual(runner.test, test)
+
+ finally:
+ TestProgram.parseArgs = oldParseArgs
+ del TestProgram.test
+
+
+ class FooBar(unittest.TestCase):
+ def testPass(self):
+ assert True
+ def testFail(self):
+ assert False
+
+ class FooBarLoader(unittest.TestLoader):
+ """Test loader that returns a suite containing FooBar."""
+ def loadTestsFromModule(self, module):
+ return self.suiteClass(
+ [self.loadTestsFromTestCase(Test_TestProgram.FooBar)])
+
+
+ def test_NonExit(self):
+ program = unittest.main(exit=False,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ testLoader=self.FooBarLoader())
+ self.assertTrue(hasattr(program, 'result'))
+
+
+ def test_Exit(self):
+ self.assertRaises(
+ SystemExit,
+ unittest.main,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ exit=True,
+ testLoader=self.FooBarLoader())
+
+
+ def test_ExitAsDefault(self):
+ self.assertRaises(
+ SystemExit,
+ unittest.main,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ testLoader=self.FooBarLoader())
+
+
+class Test_TextTestRunner(TestCase):
+ """Tests for TextTestRunner."""
+
+ def test_works_with_result_without_startTestRun_stopTestRun(self):
+ class OldTextResult(ResultWithNoStartTestRunStopTestRun):
+ separator2 = ''
+ def printErrors(self):
+ pass
+
+ class Runner(unittest.TextTestRunner):
+ def __init__(self):
+ super(Runner, self).__init__(io.StringIO())
+
+ def _makeResult(self):
+ return OldTextResult()
+
+ runner = Runner()
+ runner.run(unittest.TestSuite())
+
+ def test_startTestRun_stopTestRun_called(self):
+ class LoggingTextResult(LoggingResult):
+ separator2 = ''
+ def printErrors(self):
+ pass
+
+ class LoggingRunner(unittest.TextTestRunner):
+ def __init__(self, events):
+ super(LoggingRunner, self).__init__(io.StringIO())
+ self._events = events
+
+ def _makeResult(self):
+ return LoggingTextResult(self._events)
+
+ events = []
+ runner = LoggingRunner(events)
+ runner.run(unittest.TestSuite())
+ expected = ['startTestRun', 'stopTestRun']
+ self.assertEqual(events, expected)
+
+
######################################################################
## Main
######################################################################
@@ -3019,7 +3353,8 @@ class TestLongMessage(TestCase):
def test_main():
support.run_unittest(Test_TestCase, Test_TestLoader,
Test_TestSuite, Test_TestResult, Test_FunctionTestCase,
- Test_TestSkipping, Test_Assertions, TestLongMessage)
+ Test_TestSkipping, Test_Assertions, TestLongMessage,
+ Test_TestProgram, TestCleanUp)
if __name__ == "__main__":
test_main()