Commits

akalias  committed 7047d24

Added in more tests, fixes to gen_stubs.py, replaced run_tests.py with run_tests_sub.py (defaults to single process as b4).

  • Participants
  • Parent commits 1825f10

Comments (0)

Files changed (8)

File run_tests.py

 #!/usr/bin/env python
-import sys, os, re, unittest
+
+"""
+
+Test runner for pygame unittests:
+
+By default, runs all test/xxxx_test.py files in a single process.
+
+Option to run tests in subprocesses using subprocess and async_sub. Will poll 
+tests for return code and if tests don't return after TIME_OUT, will kill 
+process with os.kill.
+
+os.kill is defined on win32 platform using subprocess.Popen to call either 
+pskill or taskkill if on the system $PATH. If not, the script will raise 
+SystemExit.
+
+taskkill is shipped with windows from XP on.
+pskill is available from SysInternals website
+
+Dependencies:
+    async_sub.py:
+        Requires win32 extensions when run on windows:
+            Maybe able to get away with win32file.pyd, win32pipe.pyd zipped to 
+            about 35kbytes and ship with that.
+"""
+
+#################################### IMPORTS ###################################
+
+import sys, os, re, unittest, subprocess, time, optparse
+import pygame.threads, async_sub
 
 main_dir = os.path.split(os.path.abspath(sys.argv[0]))[0]
-test_subdir = 'test'
+test_subdir = os.path.join(main_dir, 'test')
+fake_test_subdir = os.path.join(test_subdir, 'run_tests__tests')
 
-# Make sure we're in the correct directory
-os.chdir( main_dir )
+sys.path.insert(0, test_subdir)
 
-# Add the modules directory to the python path    
-sys.path.insert( 0, test_subdir )
-
-# Load test util functions
 import test_utils
 
-# Load all the tests
-suite = unittest.TestSuite()
-test_module_re = re.compile('^(.+_test)\.py$')
-for file in os.listdir(test_subdir):
-    for module in test_module_re.findall(file):
-        if module == "scrap_test":
-            continue
+################################### CONSTANTS ##################################
+# Defaults:
+#    See optparse options below for more options
+#
+
+# 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
+
+# Any tests in IGNORE will not be ran
+IGNORE = (
+    "scrap_test",
+)
+
+# Subprocess has less of a need to worry about interference between tests
+SUBPROCESS_IGNORE = (
+    "scrap_test",
+)
+
+################################################################################
+
+COMPLETE_FAILURE_TEMPLATE = """
+======================================================================
+ERROR: all_tests_for (%s.AllTestCases)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "test\%s.py", line 1, in all_tests_for
+
+subprocess completely failed with return code of %s
+
+cmd: %s
+
+return (abbrv):
+%s
+
+"""  # Leave that last empty line else build page regex won't match
+
+RAN_TESTS_DIV = (70 * "-") + "\nRan"
+
+DOTS = re.compile("^([FE.]+)$", re.MULTILINE)
+
+TEST_MODULE_RE = re.compile('^(.+_test)\.py$')
+
+################################################################################
+# Set the command line options
+#
+
+USEAGE = """
+
+Runs all the test/xxxx_test.py tests.
+
+"""
+
+opt_parser = optparse.OptionParser(USEAGE)
+opt_parser.add_option(
+     "-v",  "--verbose", action = 'store_true',
+     help   = "be verbose in output (only single process mode)" )
+
+opt_parser.add_option (
+     "-i",  "--incomplete", action = 'store_true',
+     help   = "fail incomplete tests (only single process mode)" )
+
+opt_parser.add_option (
+     "-s",  "--subprocess", action = 'store_true',
+     help   = "run test suites in subprocesses (default: same process)" )
+
+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', default = TIME_OUT,
+     help   = "kill stalled subprocessed tests after SECONDS" )
+
+opt_parser.add_option (
+     "-f",  "--fake", metavar = "DIR",
+     help   = "run fake tests in %s%s$DIR"  % (fake_test_subdir, os.path.sep) )
+
+opt_parser.add_option (
+     "-p",  "--python", metavar = "PYTHON", default = sys.executable,
+     help   = "path to python excutable to run subproccesed tests\n"
+              "default (sys.executable): %s" % sys.executable)
+
+     # can be used for testing ret_code resilience
+
+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
+# this is used for testing subprocess output against single process mode
+
+if options.fake:
+    test_subdir = os.path.join(fake_test_subdir, options.fake )
+    sys.path.append(test_subdir)
+
+os.chdir(main_dir)
+
+test_modules = []
+for f in os.listdir(test_subdir):
+    for match in TEST_MODULE_RE.findall(f):
+        test_modules.append(match)
+
+################################################################################
+# Run all the tests in one process
+# unittest.TextTestRunner().run(unittest.TestSuite())
+#
+
+if not options.subprocess:
+    suite = unittest.TestSuite()
+    runner = unittest.TextTestRunner()
+        
+    for module in [m for m in test_modules if m not in IGNORE]:
         print 'loading ' + module
         __import__( module )
         test = unittest.defaultTestLoader.loadTestsFromName( module )
         suite.addTest( test )
+    
+    test_utils.fail_incomplete_tests = options.incomplete
+    if options.verbose:
+        runner.verbosity = 2
+    
+    runner.run( suite )
+    
+    sys.exit()
 
-# Parse command line options
-if "--incomplete" in sys.argv or "-i" in sys.argv:
-    test_utils.fail_incomplete_tests = 1
+    ###########################
+    # SYS.EXIT() FLOW CONTROL #
+    ###########################
 
-verbose = "--verbose" in sys.argv or "-v" in sys.argv
+################################################################################
+# Runs an individual xxxx_test.py test suite in a subprocess
+#
+def run_test(cmd):
+    module = os.path.basename(cmd).split('.')[0]
+    print 'loading %s' % module
+    ret_code, response = async_sub.proc_in_time_or_kill (
+        cmd, time_out=options.time_out
+    )
+    return cmd, module, ret_code, response
 
-# Run the tests
-runner = unittest.TextTestRunner()
+################################################################################
+# Run all the tests in subprocesses
+#
 
-if verbose: runner.verbosity = 2
-runner.run( suite )
+test_cmd = ('%s %s/' % (options.python, test_subdir)) + '%s.py'
+# test_cmd += flags and options to pass on
+
+test_cmds = [ test_cmd % m for m in test_modules if 
+                         m not in SUBPROCESS_IGNORE ]
+
+t = time.time()
+
+if options.multi_thread:
+    test_results = pygame.threads.tmap (
+        run_test, test_cmds,
+        stop_on_error = False,
+        num_workers = options.multi_thread
+    )
+else:
+    test_results = map(run_test, test_cmds)
+
+t = time.time() - t
+
+################################################################################
+# Combine subprocessed TextTestRunner() results to mimick single run
+# Puts complete failures in a form the build page will pick up
+
+all_dots = ''
+failures = []
+complete_failures = 0
+
+for cmd, module, ret_code, ret in test_results:
+    if ret_code and RAN_TESTS_DIV not in ret:
+        ret = ''.join(ret.splitlines(1)[:5])
+
+        failures.append (
+            COMPLETE_FAILURE_TEMPLATE % (module, module, ret_code, cmd, ret)
+        )
+        complete_failures += 1
+        continue
+
+    dots = DOTS.search(ret)
+    if not dots: continue                        # in case of empty xxxx_test.py
+    else: dots = dots.group(1)
+
+    all_dots += dots
+
+    if 'E' in dots or 'F' in dots:
+        failure = ret[len(dots):].split(RAN_TESTS_DIV)[0]
+        failures.append (
+            failure.replace( "(__main__.", "(%s." % module)
+        )
+
+total_fails, total_errors = all_dots.count('F'), all_dots.count('E')
+total_tests = len(all_dots)
+
+print all_dots
+if failures: print ''.join(failures).lstrip('\n')[:-1]
+print "%s %s tests in %.3fs\n" % (RAN_TESTS_DIV, total_tests, t)
+
+if not failures:
+    print 'OK'
+else:
+    print 'FAILED (%s)' % ', '.join (
+        (total_fails  and ["failures=%s" % total_fails] or []) +
+        (total_errors and ["errors=%s"  % total_errors] or [])
+    )
+
+################################################################################

File run_tests_old.py

+#!/usr/bin/env python
+import sys, os, re, unittest
+
+main_dir = os.path.split(os.path.abspath(sys.argv[0]))[0]
+test_subdir = 'test'
+
+# Make sure we're in the correct directory
+os.chdir( main_dir )
+
+# Add the modules directory to the python path    
+sys.path.insert( 0, test_subdir )
+
+# Load test util functions
+import test_utils
+
+# Load all the tests
+suite = unittest.TestSuite()
+test_module_re = re.compile('^(.+_test)\.py$')
+for file in os.listdir(test_subdir):
+    for module in test_module_re.findall(file):
+        if module == "scrap_test":
+            continue
+        print 'loading ' + module
+        __import__( module )
+        test = unittest.defaultTestLoader.loadTestsFromName( module )
+        suite.addTest( test )
+
+# Parse command line options
+if "--incomplete" in sys.argv or "-i" in sys.argv:
+    test_utils.fail_incomplete_tests = 1
+
+verbose = "--verbose" in sys.argv or "-v" in sys.argv
+
+# Run the tests
+runner = unittest.TextTestRunner()
+
+if verbose: runner.verbosity = 2
+runner.run( suite )

File run_tests_sub.py

-#!/usr/bin/env python
-
-"""
-
-Test runner for pygame unittests:
-
-By default, runs all test/xxxx_test.py files in a single process.
-
-Option to run tests in subprocesses using subprocess and async_sub. Will poll 
-tests for return code and if tests don't return after TIME_OUT, will kill 
-process with os.kill.
-
-os.kill is defined on win32 platform using subprocess.Popen to call either 
-pskill orsystem $PATH. If not, the script will raise SystemExit. 
-
-taskkill is shipped with windows from XP on.
-pskill is available from SysInternals website
-
-Dependencies:
-    async_sub.py:
-        Requires win32 extensions when Run on windows:
-            Maybe able to get away with win32file.pyd, win32pipe.pyd zipped to 
-            about 35kbytes and ship with that.
-"""
-
-#################################### IMPORTS ###################################
-
-import sys, os, re, unittest, subprocess, time, optparse
-import pygame.threads, async_sub
-
-main_dir = os.path.split(os.path.abspath(sys.argv[0]))[0]
-test_subdir = os.path.join(main_dir, 'test')
-fake_test_subdir = os.path.join(test_subdir, 'run_tests__tests')
-
-sys.path.insert(0, test_subdir)
-
-import test_utils
-
-################################### CONSTANTS ##################################
-# Defaults:
-#    See optparse options below for more options
-#
-
-# 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
-
-# Any tests in IGNORE will not be ran
-IGNORE = (
-    "scrap_test",
-)
-
-# Subprocess has less of a need to worry about interference between tests
-SUBPROCESS_IGNORE = (
-    "scrap_test",
-)
-
-################################################################################
-
-COMPLETE_FAILURE_TEMPLATE = """
-======================================================================
-ERROR: all_tests_for (%s.AllTestCases)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "test\%s.py", line 1, in all_tests_for
-
-subprocess completely failed with return code of %s
-
-cmd: %s
-
-return (abbrv):
-%s
-
-"""  # Leave that last empty line else build page regex won't match
-
-RAN_TESTS_DIV = (70 * "-") + "\nRan"
-
-DOTS = re.compile("^([FE.]+)$", re.MULTILINE)
-
-TEST_MODULE_RE = re.compile('^(.+_test)\.py$')
-
-################################################################################
-# Set the command line options
-#
-
-USEAGE = """
-
-Runs all the test/xxxx_test.py tests.
-
-"""
-
-opt_parser = optparse.OptionParser(USEAGE)
-opt_parser.add_option(
-     "-v",  "--verbose", action = 'store_true',
-     help   = "be verbose in output (only single process mode)" )
-
-opt_parser.add_option (
-     "-i",  "--incomplete", action = 'store_true',
-     help   = "fail incomplete tests (only single process mode)" )
-
-opt_parser.add_option (
-     "-s",  "--subprocess", action = 'store_true',
-     help   = "run test suites in subprocesses (default: same process)" )
-
-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', default = TIME_OUT,
-     help   = "kill stalled subprocessed tests after SECONDS" )
-
-opt_parser.add_option (
-     "-f",  "--fake", metavar = "DIR",
-     help   = "run fake tests in %s%s$DIR"  % (fake_test_subdir, os.path.sep) )
-
-opt_parser.add_option (
-     "-p",  "--python", metavar = "PYTHON", default = sys.executable,
-     help   = "path to python excutable to run subproccesed tests\n"
-              "default (sys.executable): %s" % sys.executable)
-
-     # can be used for testing ret_code resilience
-
-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
-# this is used for testing subprocess output against single process mode
-
-if options.fake:
-    test_subdir = os.path.join(fake_test_subdir, options.fake )
-    sys.path.append(test_subdir)
-
-os.chdir(main_dir)
-
-test_modules = []
-for f in os.listdir(test_subdir):
-    for match in TEST_MODULE_RE.findall(f):
-        test_modules.append(match)
-
-################################################################################
-# Run all the tests in one process
-# unittest.TextTestRunner().run(unittest.TestSuite())
-#
-
-if not options.subprocess:
-    suite = unittest.TestSuite()
-    runner = unittest.TextTestRunner()
-        
-    for module in [m for m in test_modules if m not in IGNORE]:
-        print 'loading ' + module
-        __import__( module )
-        test = unittest.defaultTestLoader.loadTestsFromName( module )
-        suite.addTest( test )
-    
-    test_utils.fail_incomplete_tests = options.incomplete
-    if options.verbose:
-        runner.verbosity = 2
-    
-    runner.run( suite )
-    
-    sys.exit()
-
-    ###########################
-    # SYS.EXIT() FLOW CONTROL #
-    ###########################
-
-################################################################################
-# Runs an individual xxxx_test.py test suite in a subprocess
-#
-def run_test(cmd):
-    module = os.path.basename(cmd).split('.')[0]
-    print 'loading %s' % module
-    ret_code, response = async_sub.proc_in_time_or_kill (
-        cmd, time_out=options.time_out
-    )
-    return cmd, module, ret_code, response
-
-################################################################################
-# Run all the tests in subprocesses
-#
-
-test_cmd = ('%s %s/' % (options.python, test_subdir)) + '%s.py'
-# test_cmd += flags and options to pass on
-
-test_cmds = [ test_cmd % m for m in test_modules if 
-                         m not in SUBPROCESS_IGNORE ]
-
-t = time.time()
-
-if options.multi_thread:
-    test_results = pygame.threads.tmap (
-        run_test, test_cmds,
-        stop_on_error = False,
-        num_workers = options.multi_thread
-    )
-else:
-    test_results = map(run_test, test_cmds)
-
-t = time.time() - t
-
-################################################################################
-# Combine subprocessed TextTestRunner() results to mimick single run
-# Puts complete failures in a form the build page will pick up
-
-all_dots = ''
-failures = []
-complete_failures = 0
-
-for cmd, module, ret_code, ret in test_results:
-    if ret_code and RAN_TESTS_DIV not in ret:
-        ret = '\n'.join(ret.split('\n')[:5])
-
-        failures.append (
-            COMPLETE_FAILURE_TEMPLATE % (module, module, ret_code, cmd, ret)
-        )
-        complete_failures += 1
-        continue
-
-    dots = DOTS.search(ret)
-    if not dots: continue                        # in case of empty xxxx_test.py
-    else: dots = dots.group(1)
-
-    all_dots += dots
-
-    if 'E' in dots or 'F' in dots:
-        failure = ret[len(dots):].split(RAN_TESTS_DIV)[0]
-        failures.append (
-            failure.replace( "(__main__.", "(%s." % module)
-        )
-
-total_fails, total_errors = all_dots.count('F'), all_dots.count('E')
-total_tests = len(all_dots)
-
-print all_dots
-if failures: print ''.join(failures).lstrip('\n')[:-1]
-print "%s %s tests in %.3fs\n" % (RAN_TESTS_DIV, total_tests, t)
-
-if not failures:
-    print 'OK'
-else:
-    print 'FAILED (%s)' % ', '.join (
-        (total_fails  and ["failures=%s" % total_fails] or []) +
-        (total_errors and ["errors=%s"  % total_errors] or [])
-    )
-
-################################################################################

File test/cdrom_test.py

           # CD.stop(): return None
           # stop audio playback
 
-        self.assert_(test_not_implemented()) 
-
-
+        self.assert_(test_not_implemented())
 
 ################################################################################
 
 if __name__ == '__main__':
     test_utils.get_fail_incomplete_tests_option()
-    unittest.main()
+    unittest.main()

File test/mixer_test.py

 ############################## CHANNEL CLASS TESTS #############################
 
 class ChannelTypeTest(unittest.TestCase):
+    
     def test_Channel(self):
       self.assert_(test_not_implemented())
+      
+    def test_fadeout(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.fadeout:
+
+          # Channel.fadeout(time): return None
+          # stop playback after fading channel out
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_busy(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.get_busy:
+
+          # Channel.get_busy(): return bool
+          # check if the channel is active
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_endevent(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.get_endevent:
+
+          # Channel.get_endevent(): return type
+          # get the event a channel sends when playback stops
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_queue(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.get_queue:
+
+          # Channel.get_queue(): return Sound
+          # return any Sound that is queued
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_sound(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.get_sound:
+
+          # Channel.get_sound(): return Sound
+          # get the currently playing Sound
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_volume(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.get_volume:
+
+          # Channel.get_volume(): return value
+          # get the volume of the playing channel
+
+        self.assert_(test_not_implemented()) 
+
+    def test_pause(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.pause:
+
+          # Channel.pause(): return None
+          # temporarily stop playback of a channel
+
+        self.assert_(test_not_implemented()) 
+
+    def test_play(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.play:
+
+          # Channel.play(Sound, loops=0, maxtime=0, fade_ms=0): return None
+          # play a Sound on a specific Channel
+
+        self.assert_(test_not_implemented()) 
+
+    def test_queue(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.queue:
+
+          # Channel.queue(Sound): return None
+          # queue a Sound object to follow the current
+
+        self.assert_(test_not_implemented()) 
+
+    def test_set_endevent(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.set_endevent:
+
+          # Channel.set_endevent(): return None
+          # Channel.set_endevent(type): return None
+          # have the channel send an event when playback stops
+
+        self.assert_(test_not_implemented()) 
+
+    def test_set_volume(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.set_volume:
+
+          # Channel.set_volume(value): return None
+          # Channel.set_volume(left, right): return None
+          # set the volume of a playing channel
+
+        self.assert_(test_not_implemented()) 
+
+    def test_stop(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.stop:
+
+          # Channel.stop(): return None
+          # stop playback on a Channel
+
+        self.assert_(test_not_implemented()) 
+
+    def test_unpause(self):
+
+        # __doc__ (as of 2008-07-02) for pygame.mixer.Channel.unpause:
+
+          # Channel.unpause(): return None
+          # resume pause playback of a channel
+
+        self.assert_(test_not_implemented()) 
+
 
 ############################### SOUND CLASS TESTS ##############################
 
 
 if __name__ == '__main__':
     test_utils.get_fail_incomplete_tests_option()
-    unittest.main()
+    unittest.main()

File test/run_tests__tests/run_tests__test.py

     'infinite_loop',
 )
 NORMALIZERS = (
-    (r"Ran (\d+) tests in (\d+\.\d+)s", "Ran \\1 tests in X.XXXs" ),
-    (r'File ".*?([^/\\.]+\.py)"', 'File "\\1"')  
+    (r"Ran (\d+) tests in (\d+\.\d+)s",   "Ran \\1 tests in X.XXXs" ),
+    (r'File ".*?([^/\\.]+\.py)"',         'File "\\1"')  
     #TODO: look into why os.path.sep differs
 )
 
 # Test that output is the same in single process and subprocess modes 
 #
 
-single_cmd = "%s run_tests_sub.py -f %s"
+single_cmd = "%s run_tests.py -f %s"
 subprocess_cmd = single_cmd + ' -s'
 
 passes = 0

File test/time_test.py

 
 ################################################################################
 
-class ClockTypeTest(unittest.TestCase):
-    def test_Clock(self):
+class ClockTypeTest(unittest.TestCase):    
+    def test_get_fps(self):
 
-        # __doc__ (as of 2008-06-25) for pygame.time.Clock:
+        # __doc__ (as of 2008-07-03) for pygame.time.Clock.get_fps:
 
-          # pygame.time.Clock(): return Clock
-          # create an object to help track time
+          # Clock.get_fps(): return float
+          # compute the clock framerate
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_rawtime(self):
+
+        # __doc__ (as of 2008-07-03) for pygame.time.Clock.get_rawtime:
+
+          # Clock.get_rawtime(): return milliseconds
+          # actual time used in the previous tick
+
+        self.assert_(test_not_implemented()) 
+
+    def test_get_time(self):
+
+        # __doc__ (as of 2008-07-03) for pygame.time.Clock.get_time:
+
+          # Clock.get_time(): return milliseconds
+          # time used in the previous tick
+
+        self.assert_(test_not_implemented()) 
+
+    def test_tick(self):
+
+        # __doc__ (as of 2008-07-03) for pygame.time.Clock.tick:
+
+          # Clock.tick(framerate=0): return milliseconds
+          # control timer events
+          # update the clock
+
+        self.assert_(test_not_implemented()) 
+
+    def test_tick_busy_loop(self):
+
+        # __doc__ (as of 2008-07-03) for pygame.time.Clock.tick_busy_loop:
+
+          # Clock.tick_busy_loop(framerate=0): return milliseconds
+          # control timer events
+          # update the clock
 
         self.assert_(test_not_implemented()) 
 
 class TimeModuleTest(unittest.TestCase):
-    def test_Clock(self):
-        # __doc__ (as of 2008-06-25) for pygame.time.Clock:
-
-          # pygame.time.Clock(): return Clock
-          # create an object to help track time
-
-        self.assert_(test_not_implemented()) 
-
     def test_delay(self):
 
         # __doc__ (as of 2008-06-25) for pygame.time.delay:

File test/util/gen_stubs.py

 # Out[7]: 'overlay'
 
 # Mapping of callable to module where it's defined
+
 REAL_HOMES = {
     pygame.rect.Rect         : pygame.rect,
     pygame.mask.from_surface : pygame.mask,
     pygame.font.get_fonts    : pygame.font,
     pygame.font.match_font   : pygame.font,
 }
+  
+MUST_INSTANTIATE = {
+    # BaseType                        # Instance
 
-# Types that need instantiating before inspection
-MUST_INSTANTIATE = {
-    pygame.cdrom.CDType          :  (pygame.cdrom.CD, (1,)),
+    pygame.cdrom.CDType            :  (pygame.cdrom.CD, (1,)),
+    pygame.mixer.ChannelType       :  (pygame.mixer.Channel, (1,)),
+    pygame.time.Clock              :  (pygame.time.Clock, ()),
 
-    # pygame.event.Event       :  None,
-    # pygame.joystick.Joystick :  None,
-    # pygame.time.Clock        :  (),
-    # pygame.mixer.Channel     :  None,
+    # pygame.event.Event         :  None,
+    # pygame.joystick.Joystick   :  None,
     # pygame.movie.Movie       :  None,
     # pygame.mask.Mask         :  None,
     # pygame.display.Info      :  None,
 }
 
-if MUST_INSTANTIATE:
+def get_instance(type_):
     pygame.init()
 
-def get_instance(type_):
     helper = MUST_INSTANTIATE.get(type_)
     if callable(helper): return helper()
     helper, arg = helper
     try:
         return helper(*arg)
     except:
-        "FAILED TO CREATE INSTANCE OF %s" % type_
+        # TODO: raise or not to raise??
+        raw_input("FAILED TO CREATE INSTANCE OF %s" % type_)
         return type_
 
 ##################################### TODO #####################################
 """
 
 Test
-    
-More instances
 
 """
 
 
 opt_parser.add_option (
      "-l",  "--list", dest = "list", action = 'store_true',
-     help   = "list only test names not stubs" )
+     help   = "list only callable names not stubs" )
 
 opt_parser.set_usage(
 """
 
 def get_callables(obj, if_of = None, check_where_defined=False):
     publics = (getattr(obj, x) for x in dir(obj) if is_public(x))
-    callables = [x for x in publics if callable(x)]
-    
+    callables = (x for x in publics if callable(x) or isgetsetdescriptor(x))
+
     if check_where_defined:
-        callables = (c for c in callables if ( 'pygame' in c.__module__ or 
+        callables = (c for c in callables if ( 'pygame' in c.__module__ or
                     ('__builtin__' == c.__module__ and isclass(c)) )
-                    and REAL_HOMES.get(c) in (None, obj))
+                    and REAL_HOMES.get(c, 0) in (0, obj))
 
     if if_of:
-        callables = [x for x in callables if if_of(x)] # isclass, ismethod etc
-    
+        callables = (x for x in callables if if_of(x)) # isclass, ismethod etc
+
     return set(callables)
 
 def get_class_from_test_case(TC):
 def names_of(*args):
     return tuple(map(lambda o: getattr(o, "__name__", str(o)), args))
 
-def callable_name(module, c, class_=None):
-    if class_:
-        return '%s.%s.%s' % names_of(module, class_, c)
-    else:
-        return '%s.%s' % names_of(module, c)
+def callable_name(*args):
+    args = [a for a in args if a]
+    return ('.'.join(['%s'] * len(args))) % names_of(*args)
 
 ################################################################################
 
 def test_stub(f, module, parent_class = None):
     test_name = 'test_%s' % f.__name__
-    unit_name = callable_name(module, f, parent_class)
+    unit_name = callable_name(module, parent_class, f)
 
     stub = STUB_TEMPLATE.render (
 
     return unit_name, stub
 
 def make_stubs(seq, module, class_=None):
-    return dict( test_stub(f, module, class_) for f in seq )
+    return dict( test_stub(c, module, class_) for c in seq )
 
 def module_stubs(module):
     stubs = {}
     all_callables = get_callables(module, check_where_defined = True)
+    classes = set (
+        c for c in all_callables if isclass(c) or c in MUST_INSTANTIATE
+    )
 
-    classes = set(c for c in all_callables if isclass(c))
-    
     for class_ in classes:
-        base_type = class_          # eg cdrom.CD has no __name__
-        
-        if class_ in MUST_INSTANTIATE: 
+        base_type = class_
+
+        if class_ in MUST_INSTANTIATE:
             class_ = get_instance(class_)
-            
-        get_set = (m[1] for m in getmembers(class_, isgetsetdescriptor))
-        get_set = set(c for c in get_set if is_public(c))
 
         stubs.update (
-            make_stubs(get_set ^ get_callables(class_), module, base_type) 
+            make_stubs(get_callables(class_), module, base_type)
         )
 
     stubs.update(make_stubs(all_callables - classes, module))
 
     return stubs
 
+################################################################################
+
 def already_tested_in_module(module):
     already = []
 
     mod_name =  module.__name__
     test_name = "%s_test" % mod_name[7:]
-    
+
     try: test_file = __import__(test_name)
-    except ImportError:
+    except ImportError:                              #TODO:  create a test file?
         return []
-    
+
     classes = get_callables(test_file, isclass)
     test_cases = (t for t in classes if TestCase in t.__bases__)
     
 
     return already
 
-def get_stubs(root):
+################################################################################
+
+def get_stubs(root):    
     module_root = module_re.search(root)
     if module_root:
         module = getattr(pygame, module_root.group(1))
 
 if __name__ == "__main__":
     options, args = opt_parser.parse_args()
-    if not sys.argv[1:]: 
+    if not sys.argv[1:]:
         sys.exit(opt_parser.print_help())
 
     root = args and args[0] or 'pygame'
 
     for fname in sorted(s for s in stubs.iterkeys() if s not in tested):
         if not fname.startswith(root): continue  # eg. module.Class
-        stub = stubs[fname]
-        print options.list and fname or stub
+        print options.list and fname or stubs[fname]
 
 ################################################################################