Anonymous avatar Anonymous committed 522cae2

Reimplemented and simplified unit test framework.

Comments (0)

Files changed (48)

 	@$(PYTHON) config/bundle_docs.py
 
 runtest:
-	@$(PYTHON) test/run_tests.py
+	@$(PYTHON) test/util/runtests.py
 
 # Do not run these in production environments! They are for testing
 # purposes only!
 	@WITH_EXPERIMENTAL=$(EXPERIMENTAL) python3.1 setup.py install
 
 testall:
-	@python2.4 test/run_tests.py
+	@python2.4 test/util/runtests.py
 	@rm -rf test/*.pyc
-	@python2.5 test/run_tests.py
+	@python2.5 test/util/runtests.py
 	@rm -rf test/*.pyc
-	@python2.6 test/run_tests.py
+	@python2.6 test/util/runtests.py
 	@rm -rf test/*.pyc
-	@python3.1 test/run_tests.py
+	@python3.1 test/util/runtests.py
 	@rm -rf test/*.pyc
 
 testall2:
                  "pygame2.sprite",
                  "pygame2.threads",
                  "pygame2.test",
+                 "pygame2.test.util",
                  "pygame2.dll",
                  ]
     package_dir = { "pygame2" : "lib",
                     "pygame2.examples" : "examples",
-                    "pygame2.sprite" : "lib/sprite",
-                    "pygame2.threads" : "lib/threads",
+                    "pygame2.sprite" : os.path.join ("lib", "sprite"),
+                    "pygame2.threads" : os.path.join ("lib", "threads"),
                     "pygame2.test" : "test",
+                    "pygame2.test.util" : os.path.join ("test", "util"),
                     }
     package_data = {
         "pygame2.examples" : find_pkg_data ("examples"),
-        "pygame2.test" : find_pkg_data ("test", ["c_api", "util"]),
         }
 
     dllfiles = [ os.path.join ("pygame2", "dll"),

src/freetype/ft_font.c

         }
 
         surface = PySDLSurface_AsSDLSurface(surface_obj);
-            
+
         if (PGFT_Render_ExistingSurface(ft, font, &render, 
                 text, surface, xpos, ypos, 
                 &fg_color, bg_color_obj ? &bg_color : NULL,

test/README.txt

-================================================================================
-= README FOR PYGAME TESTS =
-===========================
-
-================================================================================
-= run_tests.py =
-================
-
-The test runner for PyGame was developed for these purposes:
-    
-    * Per process isolation of test modules
-    * Ability to tag tests for exclusion (interactive tests etc)
-    * Record timings of tests
-
-It does this by altering the behaviour of unittest at run time. As much as
-possible each individual module was left to be fully compatible with the
-standard unittest.
-
-If an individual module is run, eg ``python test/color_test.py``, then it will
-run an unmodified version of unittest. ( unittest.main() )
-
-================================================================================
-= Writing New Tests =
-=====================
-
-See test/util/gen_stubs.py for automatic creation of test stubs
-Follow the naming convention
-
-================================================================================
-= gen_stubs.py =
-================
-
-/test/util/gen_stubs.py
-
-The gen_stubs.py utility will inspect pygame, and compile stubs of each of the
-module's callables (funcs, methods, getter/setters). It will include in the
-test's comment the __doc__ and the documentation found in the relevant xxxx.doc
-files. There is a naming convention in place that maps test names to callables
-in a one to one manner. If there are no untested (or unstubbed) callables then
-gen_stubs.py will output nothing.
-
-python gen_stubs.py --help
-
-python gen_stubs.py module >> ../test_module_to_append_to.py
-
-You will need to manually merge the stubs into relevant TestCases.
-
-================================================================================
-= Test Naming Convention =
-==========================
-
-This convention is in place so the stub generator can tell what has already been
-tested and for other introspection purposes.
-
-Each module in the pygame package has a corresponding test module in the
-test/ directory.
-
-    pygame2.base.color : base_color_test.py
-
-Each test should be named in the form, test_$funcname__$comment
-
-    Color.normalize      : test_Color_normalize__additional_note
-
-================================================================================
-= Tagging =
-===========
-
-There are three levels of tagging available, module level, TestCase level and
-individual test level.
-
-For class and module level tagging assign a tag attribute __tags__ = []
-
-Module Level Tags
------------------
-
-# some_module_test.py
-__tags__ = ['display', 'interactive']
-
-Tags are inherited by children, so all TestCases, and thus tests will inherit
-these module level tags.
-
-Class Level Tags
-----------------
-
-If you want to override a specifig tag then you can use negation.
-
-class SomeTest(unittest.TestCase):
-    __tags__ = ['-interactive']
-
-Test Level Tags
----------------
-
-The tags for individual tests are specified in the __doc__ for the test.
-
-format : |Tags:comma,separated,tags|
-
-def test_something__about_something(self):
-    """
-    |Tags:interactive,some_other_tag|
-
-    """
-
-*** NOTE *** 
-
-By default 'interactive' tags are not run
-
-python run_tests.py --exclude display,slow for exclusion of tags
-
-================================================================================
 # Python 3.x gets weird hickups with the module names, if we try to import
 # run_tests.run() directly.
 #
-if sys.version_info[0] < 3:
-    from pygame2.test.run_tests import run
-else:
-    def run ():
-        import pygame2.test.run_tests
-        pygame2.test.run_tests.run ()
+#if sys.version_info[0] < 3:
+from pygame2.test.util.runtests import run
+#else:
+#    def run ():
+#        import pygame2.test.util.run_tests
+#       pygame2.test.run_tests.run ()
 
 if __name__ == "__main__":
     run ()

test/async_sub.py

-################################################################################
-"""
-
-Modification of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
-
-"""
-
-#################################### IMPORTS ###################################
-
-import os
-import subprocess
-import errno
-import time
-import sys
-import unittest
-import tempfile
-
-def geterror ():
-    return sys.exc_info()[1]
-
-if subprocess.mswindows:
-    try:
-        import ctypes
-        from ctypes.wintypes import DWORD
-        kernel32 = ctypes.windll.kernel32
-        TerminateProcess = ctypes.windll.kernel32.TerminateProcess
-        def WriteFile(handle, data, ol = None):
-            c_written = DWORD()
-            success = ctypes.windll.kernel32.WriteFile(handle, ctypes.create_string_buffer(data), len(data), ctypes.byref(c_written), ol)
-            return ctypes.windll.kernel32.GetLastError(), c_written.value
-        def ReadFile(handle, desired_bytes, ol = None):
-            c_read = DWORD()
-            buffer = ctypes.create_string_buffer(desired_bytes+1)
-            success = ctypes.windll.kernel32.ReadFile(handle, buffer, desired_bytes, ctypes.byref(c_read), ol)
-            buffer[c_read.value] = '\0'
-            return ctypes.windll.kernel32.GetLastError(), buffer.value
-        def PeekNamedPipe(handle, desired_bytes):
-            c_avail = DWORD()
-            c_message = DWORD()
-            if desired_bytes > 0:
-                c_read = DWORD()
-                buffer = ctypes.create_string_buffer(desired_bytes+1)
-                success = ctypes.windll.kernel32.PeekNamedPipe(handle, buffer, desired_bytes, ctypes.byref(c_read), ctypes.byref(c_avail), ctypes.byref(c_message))
-                buffer[c_read.value] = '\0'
-                return buffer.value, c_avail.value, c_message.value
-            else:
-                success = ctypes.windll.kernel32.PeekNamedPipe(handle, None, desired_bytes, None, ctypes.byref(c_avail), ctypes.byref(c_message))
-                return "", c_avail.value, c_message.value
-                
-    except ImportError:
-        from win32file import ReadFile, WriteFile, TerminateProcess
-        from win32pipe import PeekNamedPipe
-        from win32api import TerminateProcess
-    import msvcrt
-    
-else:
-    from signal import SIGINT, SIGTERM, SIGKILL
-    import select
-    import fcntl
-
-################################### CONSTANTS ##################################
-
-PIPE = subprocess.PIPE
-
-################################################################################
-
-class Popen(subprocess.Popen):
-    def recv(self, maxsize=None):
-        return self._recv('stdout', maxsize)
-    
-    def recv_err(self, maxsize=None):
-        return self._recv('stderr', maxsize)
-
-    def send_recv(self, input='', maxsize=None):
-        return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
-    
-    def read_async(self,  wait=.1, e=1, tr=5, stderr=0):
-        if tr < 1:
-            tr = 1
-        x = time.time()+ wait
-        y = []
-        r = ''
-        pr = self.recv
-        if stderr:
-            pr = self.recv_err
-        while time.time() < x or r:
-            r = pr()
-            if r is None:
-                if e:
-                    raise Exception("Other end disconnected!")
-                else:
-                    break
-            elif r:
-                y.append(r)
-            else:
-                time.sleep(max((x-time.time())/tr, 0))
-        return ''.join(y)
-        
-    def send_all(self, data):
-        while len(data):
-            sent = self.send(data)
-            if sent is None:
-                raise Exception("Other end disconnected!")
-            data = buffer(data, sent)
-    
-    def get_conn_maxsize(self, which, maxsize):
-        if maxsize is None:
-            maxsize = 1024
-        elif maxsize < 1:
-            maxsize = 1
-        return getattr(self, which), maxsize
-    
-    def _close(self, which):
-        getattr(self, which).close()
-        setattr(self, which, None)
-    
-    if subprocess.mswindows:
-        def kill(self):
-            # Recipes
-            #http://me.in-berlin.de/doc/python/faq/windows.html#how-do-i-emulate-os-kill-in-windows
-            #http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462
-            
-            """kill function for Win32"""
-            TerminateProcess(int(self._handle), 0) # returns None
-
-        def send(self, input):
-            if not self.stdin:
-                return None
-
-            try:
-                x = msvcrt.get_osfhandle(self.stdin.fileno())
-                (errCode, written) = WriteFile(x, input)
-            except ValueError:
-                return self._close('stdin')
-            except (subprocess.pywintypes.error, Exception):
-                if geterror()[0] in (109, errno.ESHUTDOWN):
-                    return self._close('stdin')
-                raise
-
-            return written
-
-        def _recv(self, which, maxsize):
-            conn, maxsize = self.get_conn_maxsize(which, maxsize)
-            if conn is None:
-                return None
-            
-            try:
-                x = msvcrt.get_osfhandle(conn.fileno())
-                (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
-                if maxsize < nAvail:
-                    nAvail = maxsize
-                if nAvail > 0:
-                    (errCode, read) = ReadFile(x, nAvail, None)
-            except ValueError:
-                return self._close(which)
-            except (subprocess.pywintypes.error, Exception):
-                if geterror()[0] in (109, errno.ESHUTDOWN):
-                    return self._close(which)
-                raise
-            
-            if self.universal_newlines:
-                # Translate newlines. For Python 3.x assume read is text.
-                # If bytes then another solution is needed.
-##                read = self._translate_newlines(read)
-                read = read.replace("\r\n", "\n").replace("\r", "\n")
-            return read
-
-    else:
-        def kill(self):
-            for i, sig in enumerate([SIGTERM, SIGKILL] * 2):
-                if i % 2 == 0: os.kill(self.pid, sig)
-                time.sleep((i * (i % 2) / 5.0)  + 0.01)
-
-                killed_pid, stat = os.waitpid(self.pid, os.WNOHANG)
-                if killed_pid != 0: return
-                
-        def send(self, input):
-            if not self.stdin:
-                return None
-
-            if not select.select([], [self.stdin], [], 0)[1]:
-                return 0
-
-            try:
-                written = os.write(self.stdin.fileno(), input)
-            except OSError:
-                if geterror()[0] == errno.EPIPE: #broken pipe
-                    return self._close('stdin')
-                raise
-
-            return written
-
-        def _recv(self, which, maxsize):
-            conn, maxsize = self.get_conn_maxsize(which, maxsize)
-            if conn is None:
-                return None
-            
-            flags = fcntl.fcntl(conn, fcntl.F_GETFL)
-            if not conn.closed:
-                fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-            
-            try:
-                if not select.select([conn], [], [], 0)[0]:
-                    return ''
-                
-                r = conn.read(maxsize)
-                if not r:
-                    return self._close(which)
-    
-                if self.universal_newlines:
-                    r = r.replace("\r\n", "\n").replace("\r", "\n")
-                return r
-            finally:
-                if not conn.closed:
-                    fcntl.fcntl(conn, fcntl.F_SETFL, flags)
-
-################################################################################
-
-def proc_in_time_or_kill(cmd, time_out, wd = None, env = None):
-    proc = Popen (
-        cmd, cwd = wd, env = env,
-        stdin = subprocess.PIPE, stdout = subprocess.PIPE, 
-        stderr = subprocess.STDOUT, universal_newlines = 1
-    )
-
-    ret_code = None
-    response = []
-
-    t = time.time()
-    while ret_code is None and ((time.time() -t) < time_out):
-        ret_code = proc.poll()
-        response += [proc.read_async(wait=0.1, e=0)]
-
-    if ret_code is None:
-        ret_code = '"Process timed out (time_out = %s secs) ' % time_out
-        try:
-            proc.kill()
-            ret_code += 'and was successfully terminated"'
-        except Exception:
-            ret_code += ('and termination failed (exception: %s)"' %
-                         (geterror(),))
-
-    return ret_code, ''.join(response)
-
-################################################################################
-
-class AsyncTest(unittest.TestCase):
-    def test_proc_in_time_or_kill(self):
-        ret_code, response = proc_in_time_or_kill(
-            [sys.executable, '-c', 'while 1: pass'], time_out = 1
-        )
-        
-        self.assert_( 'rocess timed out' in ret_code )
-        self.assert_( 'successfully terminated' in ret_code )
-
-################################################################################
-
-def _example():
-    if sys.platform == 'win32':
-        shell, commands, tail = ('cmd', ('echo "hello"', 'echo "HELLO WORLD"'), '\r\n')
-    else:
-        shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')
-    
-    a = Popen(shell, stdin=PIPE, stdout=PIPE)
-    sys.stdout.write(a.read_async())
-    sys.stdout.write(" ")
-    for cmd in commands:
-        a.send_all(cmd + tail)
-        sys.stdout.write(a.read_async())
-        sys.stdout.write(" ")
-    a.send_all('exit' + tail)
-    print (a.read_async(e=0))
-    a.wait()
-
-################################################################################
-    
-if __name__ == '__main__':
-    if 1: unittest.main()
-    else: _example()

test/base_bufferproxy_test.py

 import sys
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
+import unittest
 
 from pygame2.base import BufferProxy, Color
 from pygame2.colorpalettes import VGAPALETTE

test/base_color_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
 import sys
 import math
+
+import unittest
 from pygame2.base import Color
 
 if sys.version_info >= (3, 0, 0):
         c = Color (128, 128, 128, 128)
         t = c.normalize ()
         for v in t:
-            self.assertAlmostEquals (v, 0.5, 2)
+            self.assertAlmostEquals (v, 0.5, places=2)
 
         c = Color (128, 255, 0, 52)
         t = c.normalize ()
-        self.assertAlmostEquals (t[0], 0.5, 2)
+        self.assertAlmostEquals (t[0], 0.5, places=2)
         self.assertEqual (t[1], 1.0)
         self.assertEqual (t[2], 0.0)
         # 52 / 255 ~= .20
-        self.assertAlmostEquals (t[3], 0.2, 2)
+        self.assertAlmostEquals (t[3], 0.2, places=2)
 
     def test_pygame2_base_Color_r(self):
 

test/base_font_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
+import unittest
 
 from pygame2.base import Font
 

test/base_frect_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
+import unittest
 from pygame2.base import FRect, Rect
 
 class FRectTest (unittest.TestCase):
         r5 = foo(10,20,30,40)
         r6 = foo2(10,20,30,40)
 
-        self.assertNotEqual(r5, r2)
-
+        self.assertEqual ((r5 == r2), False)
+        self.assertEqual ((r2 == r5), False)
         # because we define equality differently for this subclass.
-        self.assertEqual(r6, r2)
+        self.assertEqual ((r6 == r2), True)
 
 
         rect_list = [r1,r2,r3,r4,r6]

test/base_rect_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 from pygame2.base import Rect
 
 class RectTest (unittest.TestCase):
         r4 = Rect(10,20,30,40)
 
         class foo (Rect):
-            def __eq__(self,other):
-                return id(self) == id(other);
+            def __eq__ (self, other):
+                return id(self) == id(other)
 
         class foo2 (Rect):
             pass
 
         r5 = foo(10,20,30,40)
         r6 = foo2(10,20,30,40)
-
-        self.assertNotEqual(r5, r2)
-
+        
+        self.assertEqual ((r5 == r2), False)
+        self.assertEqual ((r2 == r5), False)
         # because we define equality differently for this subclass.
-        self.assertEqual(r6, r2)
+        self.assertEqual ((r6 == r2), True)
 
 
         rect_list = [r1,r2,r3,r4,r6]

test/base_surface_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
+import unittest
 from pygame2.base import Surface
 
 class TestSurface (Surface):

test/font_test.py

 import sys
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.font as font
 

test/freetype_base_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.freetype.base as base
 

test/freetype_font_test.py

 import os
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.freetype as ft
 import pygame2.freetype.constants as ft_const

test/mask_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import random
 import pygame2
 import pygame2.mask

test/math_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import copy
 import math
 import pygame2

test/math_vector2_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import sys, math
 import pygame2
 import pygame2.math as pmath
             v.epsilon = eps
         
         v = Vector (2);
-        self.assertAlmostEqual (v.epsilon, 0, 5)
+        self.assertAlmostEqual (v.epsilon, 0, places=5)
         v.epsilon = 0.0000004
         self.assertEqual (v.epsilon, 0.0000004)
         v.epsilon = 57293.2

test/math_vector3_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import sys, math
 import pygame2
 import pygame2.math as pmath

test/pgtestutils.py

-#
-# This file is under the public domain.
-#
-
-import os
-
-try:
-    getinput = raw_input
-except NameError:
-    getinput = input
-
-def getanswer (question):
-    answer = getinput ("%s [y/n]: " % question)
-    return answer.lower ().strip () == 'y'
-
-def doprint (text):
-    getinput ("%s (press enter to continue) " % text)
-
-class interactive (object):
-    """Simple interactive question decorator for unit test methods.
-    """
-    def __init__ (self, question):
-        self.question = question
-
-    def __call__ (self, func):
-        def wrapper (*fargs, **kw):
-            if fargs and getattr (fargs[0], "__class__", None):
-                instance = fargs[0]
-                funcargs = fargs[1:]
-                print (os.linesep)
-                func (instance, *funcargs, **kw)
-                if not getanswer (self.question):
-                    instance.fail ()
-
-        wrapper.__name__ = func.__name__
-        wrapper.__dict__.update (func.__dict__)
-        wrapper.__tags__ = [ 'interactive' ]
-        return wrapper
-
-class ignore (object):
-    """Simple ignore flag decorator."""
-    def __init__ (self, func):
-        self.func = func
-    
-    def __call__ (self):
-        pass

test/pgunittest.py

-#!/usr/bin/env python
-
-'''
-Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
-Smalltalk testing framework.
-
-This module contains the core framework classes that form the basis of
-specific test cases and suites (TestCase, TestSuite etc.), and also a
-text-based utility class for running the tests and reporting the results
- (TextTestRunner).
-
-Simple usage:
-
-    import unittest
-
-    class IntegerArithmenticTestCase(unittest.TestCase):
-        def testAdd(self):  ## test method names begin 'test*'
-            self.assertEquals((1 + 2), 3)
-            self.assertEquals(0 + 1, 1)
-        def testMultiply(self):
-            self.assertEquals((0 * 10), 0)
-            self.assertEquals((5 * 8), 40)
-
-    if __name__ == '__main__':
-        unittest.main()
-
-Further information is available in the bundled documentation, and from
-
-  http://pyunit.sourceforge.net/
-
-Copyright (c) 1999-2003 Steve Purcell
-This module is free software, and you may redistribute it and/or modify
-it under the same terms as Python itself, so long as this copyright message
-and disclaimer are retained in their original form.
-
-IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
-SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
-THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
-AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
-SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
-'''
-
-__author__ = "Steve Purcell"
-__email__ = "stephen_purcell at yahoo dot com"
-__version__ = "#Revision: 1.63 $"[11:-2]
-
-import time
-import sys
-import traceback
-import os
-import types
-
-#
-# pygame specific enhancement
-#
-try:
-    from pygame2.test.pgtestutils import *
-except:
-    from pgtestutils import *
-#
-# pygame specific enhancement END
-#
-
-##############################################################################
-# Exported classes and functions
-##############################################################################
-__all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner',
-           'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader']
-
-# Expose obsolete functions for backwards compatibility
-__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
-
-
-##############################################################################
-# Test framework core
-##############################################################################
-
-# All classes defined herein are 'new-style' classes, allowing use of 'super()'
-__metaclass__ = type
-
-def _strclass(cls):
-    return "%s.%s" % (cls.__module__, cls.__name__)
-
-__unittest = 1
-
-if sys.version_info[0] >= 3:
-    cmp = lambda x, y: (x > y) - (x < y)
-
-def CmpToKey(mycmp):
-    'Convert a cmp= function into a key= function'
-    class K(object):
-        def __init__(self, obj, *args):
-            self.obj = obj
-        def __lt__(self, other):
-            return mycmp(self.obj, other.obj) == -1
-    return K
-
-class TestResult:
-    """Holder for test result information.
-
-    Test results are automatically managed by the TestCase and TestSuite
-    classes, and do not need to be explicitly manipulated by writers of tests.
-
-    Each instance holds the total number of tests run, and collections of
-    failures and errors that occurred among those test runs. The collections
-    contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
-    formatted traceback of the error that occurred.
-    """
-    def __init__(self):
-        self.failures = []
-        self.errors = []
-        self.testsRun = 0
-        self.shouldStop = 0
-
-    def startTest(self, test):
-        "Called when the given test is about to be run"
-        self.testsRun = self.testsRun + 1
-
-    def stopTest(self, test):
-        "Called when the given test has been run"
-        pass
-
-    def addError(self, test, err):
-        """Called when an error has occurred. 'err' is a tuple of values as
-        returned by sys.exc_info().
-        """
-        self.errors.append((test, self._exc_info_to_string(err, test)))
-
-    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)))
-
-    def addSuccess(self, test):
-        "Called when a test has completed successfully"
-        pass
-
-    def wasSuccessful(self):
-        "Tells whether or not this result was a success"
-        return len(self.failures) == len(self.errors) == 0
-
-    def stop(self):
-        "Indicates that the tests should be aborted"
-        self.shouldStop = True
-
-    def _exc_info_to_string(self, err, test):
-        """Converts a sys.exc_info()-style tuple of values into a string."""
-        exctype, value, tb = err
-        # 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))
-
-    def _is_relevant_tb_level(self, tb):
-        if sys.version_info < (3,0,0):
-            return tb.tb_frame.f_globals.has_key('__unittest')
-        return '__unittest' in tb.tb_frame.f_globals
-
-    def _count_relevant_tb_levels(self, tb):
-        length = 0
-        while tb and not self._is_relevant_tb_level(tb):
-            length += 1
-            tb = tb.tb_next
-        return length
-
-    def __repr__(self):
-        return "<%s run=%i errors=%i failures=%i>" % \
-               (_strclass(self.__class__), self.testsRun, len(self.errors),
-                len(self.failures))
-
-class TestCase:
-    """A class whose instances are single test cases.
-
-    By default, the test code itself should be placed in a method named
-    'runTest'.
-
-    If the fixture may be used for many test cases, create as
-    many test methods as are needed. When instantiating such a TestCase
-    subclass, specify in the constructor arguments the name of the test method
-    that the instance is to execute.
-
-    Test authors should subclass TestCase for their own tests. Construction
-    and deconstruction of the test's environment ('fixture') can be
-    implemented by overriding the 'setUp' and 'tearDown' methods respectively.
-
-    If it is necessary to override the __init__ method, the base class
-    __init__ method must always be called. It is important that subclasses
-    should not change the signature of their __init__ method, since instances
-    of the classes are instantiated automatically by parts of the framework
-    in order to be run.
-    """
-
-    # This attribute determines which exception will be raised when
-    # the instance's assertion methods fail; test methods raising this
-    # exception will be deemed to have 'failed' rather than 'errored'
-
-    failureException = AssertionError
-
-    def __init__(self, methodName='runTest'):
-        """Create an instance of the class that will use the named test
-           method when executed. Raises a ValueError if the instance does
-           not have a method with the specified name.
-        """
-        try:
-            self._testMethodName = methodName
-            testMethod = getattr(self, methodName)
-            self._testMethodDoc = testMethod.__doc__
-        except AttributeError:
-            raise ValueError ("no such test method in %s: %s" %
-                              (self.__class__, methodName))
-
-    def setUp(self):
-        "Hook method for setting up the test fixture before exercising it."
-        pass
-
-    def tearDown(self):
-        "Hook method for deconstructing the test fixture after testing it."
-        pass
-
-    def countTestCases(self):
-        return 1
-
-    def defaultTestResult(self):
-        return TestResult()
-
-    def shortDescription(self):
-        """Returns a one-line description of the test, or None if no
-        description has been provided.
-
-        The default implementation of this method returns the first line of
-        the specified test method's docstring.
-        """
-        doc = self._testMethodDoc
-        return doc and doc.split("\n")[0].strip() or None
-
-    def id(self):
-        return "%s.%s" % (_strclass(self.__class__), self._testMethodName)
-
-    def __str__(self):
-        return "%s (%s)" % (self._testMethodName, _strclass(self.__class__))
-
-    def __repr__(self):
-        return "<%s testMethod=%s>" % \
-               (_strclass(self.__class__), self._testMethodName)
-
-    def run(self, result=None):
-        if result is None: result = self.defaultTestResult()
-        result.startTest(self)
-        testMethod = getattr(self, self._testMethodName)
-        try:
-            try:
-                self.setUp()
-            except KeyboardInterrupt:
-                raise
-            except:
-                result.addError(self, self._exc_info())
-                return
-
-            ok = False
-            try:
-                testMethod()
-                ok = True
-            except self.failureException:
-                result.addFailure(self, self._exc_info())
-            except KeyboardInterrupt:
-                raise
-            except:
-                result.addError(self, self._exc_info())
-
-            try:
-                self.tearDown()
-            except KeyboardInterrupt:
-                raise
-            except:
-                result.addError(self, self._exc_info())
-                ok = False
-            if ok: result.addSuccess(self)
-        finally:
-            result.stopTest(self)
-
-    def __call__(self, *args, **kwds):
-        return self.run(*args, **kwds)
-
-    def debug(self):
-        """Run the test without collecting errors in a TestResult"""
-        self.setUp()
-        getattr(self, self._testMethodName)()
-        self.tearDown()
-
-    def _exc_info(self):
-        """Return a version of sys.exc_info() with the traceback frame
-           minimised; usually the top level of the traceback frame is not
-           needed.
-        """
-        exctype, excvalue, tb = sys.exc_info()
-        if sys.platform[:4] == 'java': ## tracebacks look different in Jython
-            return (exctype, excvalue, tb)
-        return (exctype, excvalue, tb)
-
-    def fail(self, msg=None):
-        """Fail immediately, with the given message."""
-        raise self.failureException (msg)
-
-    def failIf(self, expr, msg=None):
-        "Fail the test if the expression is true."
-        if expr: raise self.failureException (msg)
-
-    def failUnless(self, expr, msg=None):
-        """Fail the test unless the expression is true."""
-        if not expr: raise self.failureException (msg)
-
-    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
-        """Fail unless an exception of class excClass is thrown
-           by callableObj when invoked with arguments args and keyword
-           arguments kwargs. If a different type of exception is
-           thrown, it will not be caught, and the test case will be
-           deemed to have suffered an error, exactly as for an
-           unexpected exception.
-        """
-        try:
-            callableObj(*args, **kwargs)
-        except excClass:
-            return
-        else:
-            if hasattr(excClass,'__name__'): excName = excClass.__name__
-            else: excName = str(excClass)
-            raise self.failureException ("%s not raised" % excName)
-
-    def failUnlessEqual(self, first, second, msg=None):
-        """Fail if the two objects are unequal as determined by the '=='
-           operator.
-        """
-        if not first == second:
-            raise self.failureException (msg or '%r != %r' % (first, second))
-
-    def failIfEqual(self, first, second, msg=None):
-        """Fail if the two objects are equal as determined by the '=='
-           operator.
-        """
-        if first == second:
-            raise self.failureException (msg or '%r == %r' % (first, second))
-
-    def failUnlessAlmostEqual(self, first, second, places=7, msg=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.
-
-           Note that decimal places (from zero) are usually not the same
-           as significant digits (measured from the most signficant digit).
-        """
-        if round(second-first, places) != 0:
-            raise self.failureException \
-                  (msg or '%r != %r within %r places' % (first, second, places))
-
-    def failIfAlmostEqual(self, first, second, places=7, msg=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.
-
-           Note that decimal places (from zero) are usually not the same
-           as significant digits (measured from the most signficant digit).
-        """
-        if round(second-first, places) == 0:
-            raise self.failureException \
-                  (msg or '%r == %r within %r places' % (first, second, places))
-
-    # Synonyms for assertion methods
-
-    assertEqual = assertEquals = failUnlessEqual
-
-    assertNotEqual = assertNotEquals = failIfEqual
-
-    assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual
-
-    assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual
-
-    assertRaises = failUnlessRaises
-
-    assert_ = assertTrue = failUnless
-
-    assertFalse = failIf
-
-
-
-class TestSuite:
-    """A test suite is a composite test consisting of a number of TestCases.
-
-    For use, create an instance of TestSuite, then add test case instances.
-    When all tests have been added, the suite can be passed to a test
-    runner, such as TextTestRunner. It will run the individual test cases
-    in the order in which they were added, aggregating the results. When
-    subclassing, do not forget to call the base class constructor.
-    """
-    
-    def __init__(self, tests=()):
-        self._tests = []
-        self.addTests(tests)
-
-    def __repr__(self):
-        return "<%s tests=%s>" % (_strclass(self.__class__), self._tests)
-
-    __str__ = __repr__
-
-    def __iter__(self):
-        return iter(self._tests)
-
-    def countTestCases(self):
-        cases = 0
-        for test in self._tests:
-            cases += test.countTestCases()
-        return cases
-
-    def addTest(self, test):
-        # sanity checks
-        if not hasattr (test, '__call__'):
-            raise TypeError("the test to add must be callable")
-        if (isinstance(test, type) and issubclass(test, (TestCase, TestSuite))):
-            raise TypeError("TestCases and TestSuites must be instantiated "
-                            "before passing them to addTest()")
-        self._tests.append(test)
-
-    def addTests(self, tests):
-        if isinstance(tests, str):
-            raise TypeError("tests must be an iterable of tests, not a string")
-        for test in tests:
-            self.addTest(test)
-
-    def run(self, result):
-        for test in self._tests:
-            if result.shouldStop:
-                break
-            test(result)
-        return result
-
-    def __call__(self, *args, **kwds):
-        return self.run(*args, **kwds)
-
-    def debug(self):
-        """Run the tests without collecting errors in a TestResult"""
-        for test in self._tests: test.debug()
-
-
-class FunctionTestCase(TestCase):
-    """A test case that wraps a test function.
-
-    This is useful for slipping pre-existing test functions into the
-    PyUnit framework. Optionally, set-up and tidy-up functions can be
-    supplied. As with TestCase, the tidy-up ('tearDown') function will
-    always be called if the set-up ('setUp') function ran successfully.
-    """
-
-    def __init__(self, testFunc, setUp=None, tearDown=None,
-                 description=None):
-        TestCase.__init__(self)
-        self.__setUpFunc = setUp
-        self.__tearDownFunc = tearDown
-        self.__testFunc = testFunc
-        self.__description = description
-
-    def setUp(self):
-        if self.__setUpFunc is not None:
-            self.__setUpFunc()
-
-    def tearDown(self):
-        if self.__tearDownFunc is not None:
-            self.__tearDownFunc()
-
-    def runTest(self):
-        self.__testFunc()
-
-    def id(self):
-        return self.__testFunc.__name__
-
-    def __str__(self):
-        return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__)
-
-    def __repr__(self):
-        return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc)
-
-    def shortDescription(self):
-        if self.__description is not None: return self.__description
-        doc = self.__testFunc.__doc__
-        return doc and doc.split("\n")[0].strip() or None
-
-##############################################################################
-# Locating and loading tests
-##############################################################################
-
-class TestLoader:
-    """This class is responsible for loading tests according to various
-    criteria and returning them wrapped in a Test
-    """
-    testMethodPrefix = 'test'
-    sortTestMethodsUsing = cmp
-    suiteClass = TestSuite
-
-    def loadTestsFromTestCase(self, testCaseClass):
-        """Return a suite of all tests cases contained in testCaseClass"""
-        if issubclass(testCaseClass, TestSuite):
-            raise TypeError("Test cases should not be derived from TestSuite. Maybe you meant to derive from TestCase?")
-        testCaseNames = self.getTestCaseNames(testCaseClass)
-        if not testCaseNames and hasattr(testCaseClass, 'runTest'):
-            testCaseNames = ['runTest']
-        return self.suiteClass(map(testCaseClass, testCaseNames))
-
-    def loadTestsFromModule(self, module):
-        """Return a suite of all tests cases contained in the given module"""
-        tests = []
-        for name in dir(module):
-            obj = getattr(module, name)
-            if (isinstance(obj, type) and issubclass(obj, TestCase)):
-                tests.append(self.loadTestsFromTestCase(obj))
-        return self.suiteClass(tests)
-
-    def loadTestsFromName(self, name, module=None):
-        """Return a suite of all tests cases given a string specifier.
-
-        The name may resolve either to a module, a test case class, a
-        test method within a test case class, or a callable object which
-        returns a TestCase or TestSuite instance.
-
-        The method optionally resolves the names relative to a given module.
-        """
-        parts = name.split('.')
-        if module is None:
-            parts_copy = parts[:]
-            while parts_copy:
-                try:
-                    module = __import__('.'.join(parts_copy))
-                    break
-                except ImportError:
-                    del parts_copy[-1]
-                    if not parts_copy: raise
-            parts = parts[1:]
-        obj = module
-        for part in parts:
-            parent, obj = obj, getattr(obj, part)
-
-        if type(obj) == types.ModuleType:
-            return self.loadTestsFromModule(obj)
-        elif (isinstance(obj, (type, types.ClassType)) and
-              issubclass(obj, TestCase)):
-            return self.loadTestsFromTestCase(obj)
-        elif type(obj) == types.UnboundMethodType:
-            return parent(obj.__name__)
-        elif isinstance(obj, TestSuite):
-            return obj
-        elif hasattr (obj, '__call__'):
-            test = obj()
-            if not isinstance(test, (TestCase, TestSuite)):
-                raise ValueError \
-                      ("calling %s returned %s, not a test" % (obj,test))
-            return test
-        else:
-            raise ValueError ("don't know how to make test from: %s" % obj)
-
-    def loadTestsFromNames(self, names, module=None):
-        """Return a suite of all tests cases found using the given sequence
-        of string specifiers. See 'loadTestsFromName()'.
-        """
-        suites = [self.loadTestsFromName(name, module) for name in names]
-        return self.suiteClass(suites)
-
-    def getTestCaseNames(self, testCaseClass):
-        """Return a sorted sequence of method names found within testCaseClass
-        """
-        def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix):
-            return attrname.startswith(prefix) and hasattr(getattr(testCaseClass, attrname), '__call__')
-        testFnNames = list(filter(isTestMethod, dir(testCaseClass)))
-        for baseclass in testCaseClass.__bases__:
-            for testFnName in self.getTestCaseNames(baseclass):
-                if testFnName not in testFnNames:  # handle overridden methods
-                    testFnNames.append(testFnName)
-        if self.sortTestMethodsUsing:
-            testFnNames.sort(key=CmpToKey(cmp))
-        return testFnNames
-
-
-
-defaultTestLoader = TestLoader()
-
-
-##############################################################################
-# Patches for old functions: these functions should be considered obsolete
-##############################################################################
-
-def _makeLoader(prefix, sortUsing, suiteClass=None):
-    loader = TestLoader()
-    loader.sortTestMethodsUsing = sortUsing
-    loader.testMethodPrefix = prefix
-    if suiteClass: loader.suiteClass = suiteClass
-    return loader
-
-def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
-    return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
-
-def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
-    return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
-
-def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
-    return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
-
-
-##############################################################################
-# Text UI
-##############################################################################
-
-class _WritelnDecorator:
-    """Used to decorate file-like objects with a handy 'writeln' method"""
-    def __init__(self,stream):
-        self.stream = stream
-
-    def __getattr__(self, attr):
-        return getattr(self.stream,attr)
-
-    def writeln(self, arg=None):
-        if arg: self.write(arg)
-        self.write('\n') # text-mode streams translate to \r\n if needed
-
-
-class _TextTestResult(TestResult):
-    """A test result class that can print formatted text results to a stream.
-
-    Used by TextTestRunner.
-    """
-    separator1 = '=' * 70
-    separator2 = '-' * 70
-
-    def __init__(self, stream, descriptions, verbosity):
-        TestResult.__init__(self)
-        self.stream = stream
-        self.showAll = verbosity > 1
-        self.dots = verbosity == 1
-        self.descriptions = descriptions
-
-    def getDescription(self, test):
-        if self.descriptions:
-            return test.shortDescription() or str(test)
-        else:
-            return str(test)
-
-    def startTest(self, test):
-        TestResult.startTest(self, test)
-        if self.showAll:
-            self.stream.write(self.getDescription(test))
-            self.stream.write(" ... ")
-
-    def addSuccess(self, test):
-        TestResult.addSuccess(self, test)
-        if self.showAll:
-            self.stream.writeln("ok")
-        elif self.dots:
-            self.stream.write('.')
-
-    def addError(self, test, err):
-        TestResult.addError(self, test, err)
-        if self.showAll:
-            self.stream.writeln("ERROR")
-        elif self.dots:
-            self.stream.write('E')
-
-    def addFailure(self, test, err):
-        TestResult.addFailure(self, test, err)
-        if self.showAll:
-            self.stream.writeln("FAIL")
-        elif self.dots:
-            self.stream.write('F')
-
-    def printErrors(self):
-        if self.dots or self.showAll:
-            self.stream.writeln()
-        self.printErrorList('ERROR', self.errors)
-        self.printErrorList('FAIL', self.failures)
-
-    def printErrorList(self, flavour, errors):
-        for test, err in errors:
-            self.stream.writeln(self.separator1)
-            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
-            self.stream.writeln(self.separator2)
-            self.stream.writeln("%s" % err)
-
-
-class TextTestRunner:
-    """A test runner class that displays results in textual form.
-
-    It prints out the names of tests as they are run, errors as they
-    occur, and a summary of the results at the end of the test run.
-    """
-    def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
-        self.stream = _WritelnDecorator(stream)
-        self.descriptions = descriptions
-        self.verbosity = verbosity
-
-    def _makeResult(self):
-        return _TextTestResult(self.stream, self.descriptions, self.verbosity)
-
-    def run(self, test):
-        "Run the given test case or test suite."
-        result = self._makeResult()
-        startTime = time.time()
-        test(result)
-        stopTime = time.time()
-        timeTaken = stopTime - startTime
-        result.printErrors()
-        self.stream.writeln(result.separator2)
-        run = result.testsRun
-        self.stream.writeln("Ran %d test%s in %.3fs" %
-                            (run, run != 1 and "s" or "", timeTaken))
-        self.stream.writeln()
-        if not result.wasSuccessful():
-            self.stream.write("FAILED (")
-            failed, errored = map(len, (result.failures, result.errors))
-            if failed:
-                self.stream.write("failures=%d" % failed)
-            if errored:
-                if failed: self.stream.write(", ")
-                self.stream.write("errors=%d" % errored)
-            self.stream.writeln(")")
-        else:
-            self.stream.writeln("OK")
-        return result
-
-
-
-##############################################################################
-# Facilities for running tests from the command line
-##############################################################################
-
-class TestProgram:
-    """A command-line program that runs a set of tests; this is primarily
-       for making test modules conveniently executable.
-    """
-    USAGE = """\
-Usage: %(progName)s [options] [test] [...]
-
-Options:
-  -h, --help       Show this message
-  -v, --verbose    Verbose output
-  -q, --quiet      Minimal output
-
-Examples:
-  %(progName)s                               - run default set of tests
-  %(progName)s MyTestSuite                   - run suite 'MyTestSuite'
-  %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething
-  %(progName)s MyTestCase                    - run all 'test*' test methods
-                                               in MyTestCase
-"""
-    def __init__(self, module='__main__', defaultTest=None,
-                 argv=None, testRunner=None, testLoader=defaultTestLoader):
-        if type(module) == type(''):
-            self.module = __import__(module)
-            for part in module.split('.')[1:]:
-                self.module = getattr(self.module, part)
-        else:
-            self.module = module
-        if argv is None:
-            argv = sys.argv
-        self.verbosity = 1
-        self.defaultTest = defaultTest
-        self.testRunner = testRunner
-        self.testLoader = testLoader
-        self.progName = os.path.basename(argv[0])
-        self.parseArgs(argv)
-        self.runTests()
-
-    def usageExit(self, msg=None):
-        if msg: print (msg)
-        print (self.USAGE % self.__dict__)
-        sys.exit(2)
-
-    def parseArgs(self, argv):
-        import getopt
-        try:
-            options, args = getopt.getopt(argv[1:], 'hHvq',
-                                          ['help','verbose','quiet'])
-            for opt, value in options:
-                if opt in ('-h','-H','--help'):
-                    self.usageExit()
-                if opt in ('-q','--quiet'):
-                    self.verbosity = 0
-                if opt in ('-v','--verbose'):
-                    self.verbosity = 2
-            if len(args) == 0 and self.defaultTest is None:
-                self.test = self.testLoader.loadTestsFromModule(self.module)
-                return
-            if len(args) > 0:
-                self.testNames = args
-            else:
-                self.testNames = (self.defaultTest,)
-            self.createTests()
-        except getopt.error:
-            self.usageExit(sys.exc_info()[1])
-
-    def createTests(self):
-        self.test = self.testLoader.loadTestsFromNames(self.testNames,
-                                                       self.module)
-
-    def runTests(self):
-        if self.testRunner is None:
-            self.testRunner = TextTestRunner(verbosity=self.verbosity)
-        result = self.testRunner.run(self.test)
-        sys.exit(not result.wasSuccessful())
-
-main = TestProgram
-
-##############################################################################
-# Executing this module from the command line
-##############################################################################
-
-if __name__ == "__main__":
-    main(module=None)

test/run_tests.py

-#################################### IMPORTS ###################################
-import sys
-import os
-import re
-import subprocess
-import time
-import optparse
-import pygame2.threads, pygame2
-import random
-
-try:
-    from pygame2.test.test_runner import prepare_test_env, run_test, \
-         combine_results, test_failures, get_test_results, from_namespace, \
-         TEST_RESULTS_START
-except:
-    from test_runner import prepare_test_env, run_test, combine_results, \
-         test_failures, get_test_results, from_namespace, \
-         TEST_RESULTS_START
-
-from pprint import pformat
-
-main_dir, test_subdir, fake_test_subdir = \
-          prepare_test_env(os.path.abspath(__file__))
-test_runner_py = os.path.join(main_dir, "test_runner.py")
-
-try:
-    import pygame2.test.unittest_patch as unittest_patch
-except:
-    import unittest_patch as unittest_patch
-
-def run ():
-    global test_subdir
-    global main_dir
-    global fake_test_subdir
-    ############################# CONSTANTS ##############################
-    # Defaults:
-    #    See optparse options below for more options (test_runner.py)
-    #
-    #######################################################################
-    # Set the command line options
-    #
-    # Defined in test_runner.py as it shares options, added to here
-    try:
-        from pygame2.test.test_runner import opt_parser
-    except:
-        from test_runner import opt_parser
-
-    opt_parser.set_usage("""
-
-    Runs all or some of the test/xxxx_test.py tests.
-
-    $ run_tests.py sprite threads -sd
-
-    Runs the sprite and threads module tests isolated in subprocesses,
-    dumping all failing tests info in the form of a dict.
-
-    """)
-
-    options, args = opt_parser.parse_args()
-
-    ########################################################################
-    # Change to working directory and compile a list of test modules If
-    # options.fake, then compile list of fake xxxx_test.py from
-    # run_tests__tests
-
-    TEST_MODULE_RE = re.compile('^(.+_test)\.py$')
-
-    if options.fake:
-        test_subdir = os.path.join(fake_test_subdir, options.fake )
-        sys.path.append(test_subdir)
-        working_dir = test_subdir
-    else:
-        working_dir = main_dir
-
-    # Added in because some machines will need os.environ else there
-    # will be false failures in subprocess mode. Same issue as
-    # python2.6. Needs some env vars.
-    test_env = os.environ.copy()
-    test_env["PYTHONPATH"] = os.pathsep.join (
-        [pth for pth in ([test_subdir] + [test_env.get("PYTHONPATH")]) if pth]
-        )
-
-    os.chdir(working_dir)
-
-    if args:
-        test_modules = [
-            m.endswith('_test') and m or ('%s_test' % m) for m in args
-            ]
-    else:
-
-        test_modules = []
-        for f in sorted(os.listdir(test_subdir)):
-            for match in TEST_MODULE_RE.findall(f):
-                test_modules.append(match)
-
-    #######################################################################
-    # Meta results
-
-    results = {}
-    meta_results = {'__meta__' : {}}
-    meta = meta_results['__meta__']
-
-    #######################################################################
-    # Randomization
-
-    if options.randomize or options.seed:
-        seed = options.seed or time.time()
-        meta['random_seed'] = seed
-        print ("\nRANDOM SEED USED: %s\n" % seed)
-        random.seed(seed)
-        random.shuffle(test_modules)
-        
-    #######################################################################
-    # Single process mode
-
-    if not options.subprocess:
-        unittest_patch.patch(options)
-
-        t = time.time()
-        for module in test_modules:
-            results.update(run_test(module, options = options))
-        t = time.time() - t
-
-    ######################################################################
-    # Subprocess mode
-    #
-
-    if options.subprocess:
-        from async_sub import proc_in_time_or_kill
-
-        def sub_test(module):
-            print ('loading %s' % module)
-
-            pass_on_args = [a for a in sys.argv[1:] if a not in args]
-            cmd = [options.python, test_runner_py, module ] + pass_on_args
-
-            return module, (cmd, test_env, working_dir), proc_in_time_or_kill (
-                cmd, options.time_out,  env = test_env,  wd = working_dir,
-                )
-
-        if options.multi_thread:
-            def tmap(f, args):
-                return pygame2.threads.tmap (
-                    f, args, stop_on_error = False,
-                    num_workers = options.multi_thread
-                    )
-        else: tmap = map
-
-        t = time.time()
-
-        for module, cmd, (return_code, raw_return) in \
-                tmap(sub_test, test_modules):
-            test_file = '%s.py' % os.path.join(test_subdir, module)
-            cmd, test_env, working_dir = cmd
-
-            test_results = get_test_results(raw_return)
-            if test_results: results.update(test_results)
-            else: results[module] = {}
-
-            add_to_results = [
-                'return_code', 'raw_return',  'cmd', 'test_file',
-                'test_env', 'working_dir', 'module',
-                ]
-
-            results[module].update(from_namespace(locals(), add_to_results))
-    
-        t = time.time() -t
-
-    ######################################################################
-    # Output Results
-    #
-
-    untrusty_total, combined = combine_results(results, t)
-    total, fails = test_failures(results)
-
-    meta['total_tests'] = total
-    meta['combined'] = combined
-    results.update(meta_results)
-
-    if not options.subprocess:
-        assert total == untrusty_total
-
-    if not options.dump:
-        print (combined)
-    else:
-        results = options.all and results or fails
-        print (TEST_RESULTS_START)
-        print (pformat(results))
-
-    if options.file:
-        results_file = open(options.file, 'w')
-        try:        results_file.write(pformat(results))
-        finally:    results_file.close()
-
-if __name__ == "__main__":
-    run ()

test/sdl_audio_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.audio as audio
 import pygame2.sdl.constants as constants

test/sdl_base_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.base as base
 import pygame2.sdl.constants as constants

test/sdl_cdrom_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-    from pygame2.test.pgunittest import doprint, interactive
-except:
-    import pgunittest as unittest
-    from pgunittest import doprint, interactive
-
+import unittest
 import pygame2
 import pygame2.sdl.cdrom as cdrom
 import pygame2.sdl.constants as constants
 
+try:
+    from pygame2.test.util.testutils import interactive, doprint
+except ImportError:
+    from util.testutils import interactive, doprint
+
 class SDLCDRomTest (unittest.TestCase):
 
     def todo_test_pygame2_sdl_cdrom_CD_close(self):

test/sdl_cursors_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.cursors as cursors
 import pygame2.sdl.constants as constants

test/sdl_event_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.event as event
 import pygame2.sdl.constants as constants

test/sdl_gl_test.py

 import os, sys
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.video as video
 import pygame2.sdl.gl as gl

test/sdl_image_test.py

 import os, sys
+import unittest
 try:
     import StringIO as stringio
 except ImportError:
     import io as stringio
 
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
 import pygame2
 import pygame2.sdl.image as image
 import pygame2.sdl.video as video

test/sdl_joystick_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.joystick as joystick
 import pygame2.sdl.video as video

test/sdl_keyboard_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-    from pygame2.test.pgunittest import doprint, interactive
-except:
-    import pgunittest as unittest
-    from pgunittest import doprint, interactive
-
+import unittest
 import pygame2
 import pygame2.sdl.keyboard as keyboard
 import pygame2.sdl.video as video

test/sdl_mouse_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.mouse as image
 import pygame2.sdl.video as video

test/sdl_time_test.py

 import time
-try:
-    import pygame2.test.pgunittest as unittest
-    from pygame2.test.pgunittest import doprint, interactive
-except:
-    import pgunittest as unittest
-    from pgunittest import doprint, interactive
-
+import unittest
 import pygame2
 import pygame2.sdl as sdl
 import pygame2.sdl.time as sdltime

test/sdl_video_overlay_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.video as video
 import pygame2.sdl.constants as constants

test/sdl_video_pixelformat_test.py

 import sys
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 from pygame2.colorpalettes import CGAPALETTE
 from pygame2 import Rect, Color

test/sdl_video_surface_blit_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 from pygame2.colorpalettes import CGAPALETTE
 from pygame2 import Color, Rect

test/sdl_video_surface_test.py

 import sys
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
+import unittest
 
 try:
     import StringIO as stringio

test/sdl_video_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import pygame2
 import pygame2.sdl.video as video
 import pygame2.sdl.constants as constants

test/sdl_wm_test.py

 import os
-try:
-    import pygame2.test.pgunittest as unittest
-    from pygame2.test.pgunittest import doprint, interactive
-except:
-    import pgunittest as unittest
-    from pgunittest import doprint, interactive
-
+import unittest
 import pygame2
 import pygame2.sdl.wm as wm
 import pygame2.sdl.video as video
 import pygame2.sdl.constants as constants
 
+try:
+    from pygame2.test.util.testutils import interactive
+except ImportError:
+    from util.testutils import interactive
+
 class SDLWMTest (unittest.TestCase):
 
     def test_pygame2_sdl_wm_get_caption(self):

test/sdlgfx_base_test.py

-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
+import unittest
 import time
 import pygame2
 import pygame2.sdlgfx.base as base

test/test_runner.py

-################################################################################
-
-try:
-    import pygame2.test.pgunittest as unittest
-except:
-    import pgunittest as unittest
-
-import sys, os, re, time, optparse
-try:
-    import StringIO as stringio
-except:
-    import io as stringio
-from inspect import getdoc, getmembers, isclass
-from pprint import pformat
-
-try:
-    import pygame2.test.unittest_patch as unittest_patch
-    from pygame2.test.unittest_patch import StringIOContents
-except:
-    import unittest_patch
-    from unittest_patch import StringIOContents
-
-################################################################################
-
-def prepare_test_env(directory):
-    main_dir = os.path.split(directory)[0]
-    test_subdir = main_dir #os.path.join (main_dir, "test")
-    sys.path.insert(0, test_subdir)
-    fake_test_subdir = os.path.join(test_subdir, 'run_tests__tests')
-    return main_dir, test_subdir, fake_test_subdir
-
-main_dir, test_subdir, fake_test_subdir = \
-          prepare_test_env(os.path.abspath(__file__))
-
-################################################################################
-# Set the command line options
-#
-# options are shared with run_tests.py so make sure not to conflict
-# in time more will be added here
-
-opt_parser = optparse.OptionParser()
-
-opt_parser.add_option (
-     "-s",  "--subprocess", action = 'store_true',
-     help   = "run everything in an own subprocess (default: single process)" )
-
-opt_parser.add_option (
-     "-d",  "--dump", action = 'store_true',
-     help   = "dump failures/errors as dict ready to eval" )
-
-opt_parser.add_option (
-     "-F",  "--file",
-     help   = "dump failures/errors to a file" )
-
-opt_parser.add_option (
-     "-T",  "--timings", type = 'int', default = 1, metavar = 'T',
-     help   = "get timings for individual tests.\n" 
-              "Run test T times, giving average time")
-
-opt_parser.add_option (
-     "-e",  "--exclude",
-     help   = "exclude tests containing any of TAGS" )
-
-opt_parser.add_option (
-     "-w",  "--show_output", action = 'store_true',
-     help   = "show silenced stderr/stdout on errors" )
-
-opt_parser.add_option (
-     "-a",  "--all", action = 'store_true',
-     help   = "dump all results not just errors eg. -da" )
-
-opt_parser.add_option (
-     "-r",  "--randomize", action = 'store_true',
-     help   = "randomize order of tests" )
-
-opt_parser.add_option (
-     "-S",  "--seed", type = 'int',
-     help   = "seed randomizer" )
-
-opt_parser.add_option (
-     "-m",  "--multi_thread", metavar = 'THREADS', type = 'int',
-     help   = "run subprocessed tests in x THREADS" )
-
-opt_parser.add_option (
-     "-t",  "--time_out", metavar = 'SECONDS', type = 'int',
-     help   = "kill stalled subprocessed tests after SECONDS" )
-
-opt_parser.add_option (
-     "-f",  "--fake", metavar = "DIR",
-     help   = "run fake tests in run_tests__tests/$DIR" )
-
-opt_parser.add_option (
-     "-p",  "--python", metavar = "PYTHON",
-     help   = "path to python excutable to run subproccesed tests\n"
-              "default (sys.executable): %s" % sys.executable)
-
-################################################################################
-
-# If an xxxx_test.py takes longer than TIME_OUT seconds it will be killed
-# This is only the default, can be over-ridden on command line
-
-TIME_OUT = 30
-
-# DEFAULTS
-
-opt_parser.set_defaults (
-    python = sys.executable,
-    time_out = TIME_OUT,
-    exclude = 'interactive',
-)
-
-################################################################################
-# Human readable output
-#
-
-COMPLETE_FAILURE_TEMPLATE = """
-======================================================================
-ERROR: all_tests_for (%(module)s.AllTestCases)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "test/%(module)s.py", line 1, in all_tests_for
-subprocess completely failed with return code of %(return_code)s
-cmd:          %(cmd)s
-test_env:     %(test_env)s
-working_dir:  %(working_dir)s
-return (top 5 lines):
-%(raw_return)s
-
-"""  # Leave that last empty line else build page regex won't match
-     # Text also needs to be vertically compressed
-    
-
-RAN_TESTS_DIV = (70 * "-") + "\nRan"
-
-DOTS = re.compile("^([FE.]*)$", re.MULTILINE)
-
-def combine_results(all_results, t):
-    """
-
-    Return pieced together results in a form fit for human consumption. Don't
-    rely on results if  piecing together subprocessed  results (single process
-    mode is fine). Was originally meant for that  purpose but was found to be
-    unreliable.  See options.dump or options.human for reliable results.
-
-    """
-
-    all_dots = ''
-    failures = []
-
-    for module, results in sorted(all_results.items()):
-        output, return_code, raw_return = map (
-            results.get, ('output','return_code', 'raw_return')
-        )
-
-        if not output or (return_code and RAN_TESTS_DIV not in output):
-            # would this effect the original dict? TODO
-            results['raw_return'] = ''.join(raw_return.splitlines(1)[:5])
-            failures.append( COMPLETE_FAILURE_TEMPLATE % results )
-            all_dots += 'E'
-            continue