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.
........
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 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 @@
         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 @@
     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 @@
         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 @@
             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 @@
         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 @@
             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 @@
 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 @@
         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 @@
         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 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,21 +2129,32 @@
         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')
-
-            def tearDown(self):
-                events.append('tearDown')
-
-        Foo('test').run(result)
+        Foo(events).run(result)
         expected = ['startTest', 'setUp', 'addError', 'stopTest']
         self.assertEqual(events, expected)
 
+    # "With a temporary result stopTestRun is called when setUp errors.
+    def test_run_call_order__error_in_setUp_default_result(self):
+        events = []
+
+        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
     # prior to each test. Likewise, if a tearDown() method is defined, the
     # test runner will invoke that method after each test. In the example,
@@ -2093,20 +2166,32 @@
         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 @@
         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 @@
         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 @@
         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 @@
         # 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 @@
                              "^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 @@
 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()