Closes #22060: Merge with 3.4

This commit is contained in:
Zachary Ware 2014-08-08 13:35:11 -05:00
commit d630e0070f
9 changed files with 73 additions and 301 deletions

View File

@ -1,216 +1,14 @@
import os, sys, unittest, getopt, time import os
import unittest
from test import support
use_resources = [] # skip tests if _ctypes was not built
ctypes = support.import_module('ctypes')
import ctypes
ctypes_symbols = dir(ctypes) ctypes_symbols = dir(ctypes)
def need_symbol(name): def need_symbol(name):
return unittest.skipUnless(name in ctypes_symbols, return unittest.skipUnless(name in ctypes_symbols,
'{!r} is required'.format(name)) '{!r} is required'.format(name))
def load_tests(*args):
class ResourceDenied(unittest.SkipTest): return support.load_package_tests(os.path.dirname(__file__), *args)
"""Test skipped because it requested a disallowed resource.
This is raised when a test calls requires() for a resource that
has not be enabled. Resources are defined by test modules.
"""
def is_resource_enabled(resource):
"""Test whether a resource is enabled.
If the caller's module is __main__ then automatically return True."""
if sys._getframe().f_back.f_globals.get("__name__") == "__main__":
return True
result = use_resources is not None and \
(resource in use_resources or "*" in use_resources)
if not result:
_unavail[resource] = None
return result
_unavail = {}
def requires(resource, msg=None):
"""Raise ResourceDenied if the specified resource is not available.
If the caller's module is __main__ then automatically return True."""
# see if the caller's module is __main__ - if so, treat as if
# the resource was set
if sys._getframe().f_back.f_globals.get("__name__") == "__main__":
return
if not is_resource_enabled(resource):
if msg is None:
msg = "Use of the `%s' resource not enabled" % resource
raise ResourceDenied(msg)
def find_package_modules(package, mask):
import fnmatch
if (package.__loader__ is not None and
hasattr(package.__loader__, '_files')):
path = package.__name__.replace(".", os.path.sep)
mask = os.path.join(path, mask)
for fnm in package.__loader__._files.keys():
if fnmatch.fnmatchcase(fnm, mask):
yield os.path.splitext(fnm)[0].replace(os.path.sep, ".")
else:
path = package.__path__[0]
for fnm in os.listdir(path):
if fnmatch.fnmatchcase(fnm, mask):
yield "%s.%s" % (package.__name__, os.path.splitext(fnm)[0])
def get_tests(package, mask, verbosity, exclude=()):
"""Return a list of skipped test modules, and a list of test cases."""
tests = []
skipped = []
for modname in find_package_modules(package, mask):
if modname.split(".")[-1] in exclude:
skipped.append(modname)
if verbosity > 1:
print("Skipped %s: excluded" % modname, file=sys.stderr)
continue
try:
mod = __import__(modname, globals(), locals(), ['*'])
except (ResourceDenied, unittest.SkipTest) as detail:
skipped.append(modname)
if verbosity > 1:
print("Skipped %s: %s" % (modname, detail), file=sys.stderr)
continue
for name in dir(mod):
if name.startswith("_"):
continue
o = getattr(mod, name)
if type(o) is type(unittest.TestCase) and issubclass(o, unittest.TestCase):
tests.append(o)
return skipped, tests
def usage():
print(__doc__)
return 1
def test_with_refcounts(runner, verbosity, testcase):
"""Run testcase several times, tracking reference counts."""
import gc
import ctypes
ptc = ctypes._pointer_type_cache.copy()
cfc = ctypes._c_functype_cache.copy()
wfc = ctypes._win_functype_cache.copy()
# when searching for refcount leaks, we have to manually reset any
# caches that ctypes has.
def cleanup():
ctypes._pointer_type_cache = ptc.copy()
ctypes._c_functype_cache = cfc.copy()
ctypes._win_functype_cache = wfc.copy()
gc.collect()
test = unittest.makeSuite(testcase)
for i in range(5):
rc = sys.gettotalrefcount()
runner.run(test)
cleanup()
COUNT = 5
refcounts = [None] * COUNT
for i in range(COUNT):
rc = sys.gettotalrefcount()
runner.run(test)
cleanup()
refcounts[i] = sys.gettotalrefcount() - rc
if filter(None, refcounts):
print("%s leaks:\n\t" % testcase, refcounts)
elif verbosity:
print("%s: ok." % testcase)
class TestRunner(unittest.TextTestRunner):
def run(self, test, skipped):
"Run the given test case or test suite."
# Same as unittest.TextTestRunner.run, except that it reports
# skipped tests.
result = self._makeResult()
startTime = time.time()
test(result)
stopTime = time.time()
timeTaken = stopTime - startTime
result.printErrors()
self.stream.writeln(result.separator2)
run = result.testsRun
if _unavail: #skipped:
requested = list(_unavail.keys())
requested.sort()
self.stream.writeln("Ran %d test%s in %.3fs (%s module%s skipped)" %
(run, run != 1 and "s" or "", timeTaken,
len(skipped),
len(skipped) != 1 and "s" or ""))
self.stream.writeln("Unavailable resources: %s" % ", ".join(requested))
else:
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
def main(*packages):
try:
opts, args = getopt.getopt(sys.argv[1:], "rqvu:x:")
except getopt.error:
return usage()
verbosity = 1
search_leaks = False
exclude = []
for flag, value in opts:
if flag == "-q":
verbosity -= 1
elif flag == "-v":
verbosity += 1
elif flag == "-r":
try:
sys.gettotalrefcount
except AttributeError:
print("-r flag requires Python debug build", file=sys.stderr)
return -1
search_leaks = True
elif flag == "-u":
use_resources.extend(value.split(","))
elif flag == "-x":
exclude.extend(value.split(","))
mask = "test_*.py"
if args:
mask = args[0]
for package in packages:
run_tests(package, mask, verbosity, search_leaks, exclude)
def run_tests(package, mask, verbosity, search_leaks, exclude):
skipped, testcases = get_tests(package, mask, verbosity, exclude)
runner = TestRunner(verbosity=verbosity)
suites = [unittest.makeSuite(o) for o in testcases]
suite = unittest.TestSuite(suites)
result = runner.run(suite, skipped)
if search_leaks:
# hunt for refcount leaks
runner = BasicTestRunner()
for t in testcases:
test_with_refcounts(runner, verbosity, t)
return bool(result.errors)
class BasicTestRunner:
def run(self, test):
result = unittest.TestResult()
test(result)
return result

View File

@ -0,0 +1,4 @@
from ctypes.test import load_tests
import unittest
unittest.main()

View File

@ -1,19 +0,0 @@
"""Usage: runtests.py [-q] [-r] [-v] [-u resources] [mask]
Run all tests found in this directory, and print a summary of the results.
Command line flags:
-q quiet mode: don't print anything while the tests are running
-r run tests repeatedly, look for refcount leaks
-u<resources>
Add resources to the lits of allowed resources. '*' allows all
resources.
-v verbose mode: print the test currently executed
-x<test1[,test2...]>
Exclude specified tests.
mask mask to select filenames containing testcases, wildcards allowed
"""
import sys
import ctypes.test
if __name__ == "__main__":
sys.exit(ctypes.test.main(ctypes.test))

View File

@ -1,59 +1,57 @@
import unittest import unittest
import os import os
import sys import sys
import test.support
from ctypes import * from ctypes import *
from ctypes.util import find_library from ctypes.util import find_library
from ctypes.test import is_resource_enabled
if sys.platform == "win32": # On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
class Test_OpenGL_libs(unittest.TestCase):
@classmethod
def setUpClass(cls):
lib_gl = lib_glu = lib_gle = None
if sys.platform == "win32":
lib_gl = find_library("OpenGL32") lib_gl = find_library("OpenGL32")
lib_glu = find_library("Glu32") lib_glu = find_library("Glu32")
lib_gle = None elif sys.platform == "darwin":
elif sys.platform == "darwin":
lib_gl = lib_glu = find_library("OpenGL") lib_gl = lib_glu = find_library("OpenGL")
lib_gle = None else:
else:
lib_gl = find_library("GL") lib_gl = find_library("GL")
lib_glu = find_library("GLU") lib_glu = find_library("GLU")
lib_gle = find_library("gle") lib_gle = find_library("gle")
## print, for debugging ## print, for debugging
if is_resource_enabled("printing"): if test.support.verbose:
if lib_gl or lib_glu or lib_gle:
print("OpenGL libraries:") print("OpenGL libraries:")
for item in (("GL", lib_gl), for item in (("GL", lib_gl),
("GLU", lib_glu), ("GLU", lib_glu),
("gle", lib_gle)): ("gle", lib_gle)):
print("\t", item) print("\t", item)
cls.gl = cls.glu = cls.gle = None
# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
class Test_OpenGL_libs(unittest.TestCase):
def setUp(self):
self.gl = self.glu = self.gle = None
if lib_gl: if lib_gl:
self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
if lib_glu: if lib_glu:
self.glu = CDLL(lib_glu, RTLD_GLOBAL) cls.glu = CDLL(lib_glu, RTLD_GLOBAL)
if lib_gle: if lib_gle:
try: try:
self.gle = CDLL(lib_gle) cls.gle = CDLL(lib_gle)
except OSError: except OSError:
pass pass
@unittest.skipUnless(lib_gl, 'lib_gl not available')
def test_gl(self): def test_gl(self):
if self.gl: if self.gl is None:
self.skipTest('lib_gl not available')
self.gl.glClearIndex self.gl.glClearIndex
@unittest.skipUnless(lib_glu, 'lib_glu not available')
def test_glu(self): def test_glu(self):
if self.glu: if self.glu is None:
self.skipTest('lib_glu not available')
self.glu.gluBeginCurve self.glu.gluBeginCurve
@unittest.skipUnless(lib_gle, 'lib_gle not available')
def test_gle(self): def test_gle(self):
if self.gle: if self.gle is None:
self.skipTest('lib_gle not available')
self.gle.gleGetJoinStyle self.gle.gleGetJoinStyle
# On platforms where the default shared library suffix is '.so', # On platforms where the default shared library suffix is '.so',

View File

@ -1,37 +1,42 @@
from ctypes import * from ctypes import *
import sys, unittest
import os import os
import sys
import unittest
import test.support
from ctypes.util import find_library from ctypes.util import find_library
from ctypes.test import is_resource_enabled
libc_name = None libc_name = None
if os.name == "nt":
def setUpModule():
global libc_name
if os.name == "nt":
libc_name = find_library("c") libc_name = find_library("c")
elif os.name == "ce": elif os.name == "ce":
libc_name = "coredll" libc_name = "coredll"
elif sys.platform == "cygwin": elif sys.platform == "cygwin":
libc_name = "cygwin1.dll" libc_name = "cygwin1.dll"
else: else:
libc_name = find_library("c") libc_name = find_library("c")
if is_resource_enabled("printing"): if test.support.verbose:
print("libc_name is", libc_name) print("libc_name is", libc_name)
class LoaderTest(unittest.TestCase): class LoaderTest(unittest.TestCase):
unknowndll = "xxrandomnamexx" unknowndll = "xxrandomnamexx"
@unittest.skipUnless(libc_name is not None, 'could not find libc')
def test_load(self): def test_load(self):
if libc_name is None:
self.skipTest('could not find libc')
CDLL(libc_name) CDLL(libc_name)
CDLL(os.path.basename(libc_name)) CDLL(os.path.basename(libc_name))
self.assertRaises(OSError, CDLL, self.unknowndll) self.assertRaises(OSError, CDLL, self.unknowndll)
@unittest.skipUnless(libc_name is not None, 'could not find libc')
@unittest.skipUnless(libc_name is not None and
os.path.basename(libc_name) == "libc.so.6",
'wrong libc path for test')
def test_load_version(self): def test_load_version(self):
if libc_name is None:
self.skipTest('could not find libc')
if os.path.basename(libc_name) != 'libc.so.6':
self.skipTest('wrong libc path for test')
cdll.LoadLibrary("libc.so.6") cdll.LoadLibrary("libc.so.6")
# linux uses version, libc 9 should not exist # linux uses version, libc 9 should not exist
self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9") self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9")
@ -48,7 +53,7 @@ class LoaderTest(unittest.TestCase):
'test specific to Windows (NT/CE)') 'test specific to Windows (NT/CE)')
def test_load_library(self): def test_load_library(self):
self.assertIsNotNone(libc_name) self.assertIsNotNone(libc_name)
if is_resource_enabled("printing"): if test.support.verbose:
print(find_library("kernel32")) print(find_library("kernel32"))
print(find_library("user32")) print(find_library("user32"))

View File

@ -1,7 +1,6 @@
from ctypes import * from ctypes import *
import unittest, sys import unittest, sys
from test import support from test import support
from ctypes.test import requires
################################################################ ################################################################
# This section should be moved into ctypes\__init__.py, when it's ready. # This section should be moved into ctypes\__init__.py, when it's ready.
@ -39,12 +38,8 @@ class PythonAPITestCase(unittest.TestCase):
del pyob del pyob
self.assertEqual(grc(s), refcnt) self.assertEqual(grc(s), refcnt)
# This test is unreliable, because it is possible that code in
# unittest changes the refcount of the '42' integer. So, it
# is disabled by default.
@support.refcount_test @support.refcount_test
def test_PyLong_Long(self): def test_PyLong_Long(self):
requires("refcount")
ref42 = grc(42) ref42 = grc(42)
pythonapi.PyLong_FromLong.restype = py_object pythonapi.PyLong_FromLong.restype = py_object
self.assertEqual(pythonapi.PyLong_FromLong(42), 42) self.assertEqual(pythonapi.PyLong_FromLong(42), 42)

View File

@ -1,7 +1,6 @@
# Windows specific tests # Windows specific tests
from ctypes import * from ctypes import *
from ctypes.test import requires
import unittest, sys import unittest, sys
from test import support from test import support
@ -42,7 +41,6 @@ class FunctionCallTestCase(unittest.TestCase):
@unittest.skipIf(sys.executable.endswith('_d.exe'), @unittest.skipIf(sys.executable.endswith('_d.exe'),
"SEH not enabled in debug builds") "SEH not enabled in debug builds")
def test_SEH(self): def test_SEH(self):
requires("SEH")
# Call functions with invalid arguments, and make sure # Call functions with invalid arguments, and make sure
# that access violations are trapped and raise an # that access violations are trapped and raise an
# exception. # exception.

View File

@ -1,16 +1,6 @@
import unittest import unittest
from test.support import import_module from ctypes.test import load_tests
# Skip tests if _ctypes module was not built.
import_module('_ctypes')
import ctypes.test
def load_tests(*args):
skipped, testcases = ctypes.test.get_tests(ctypes.test, "test_*.py", verbosity=0)
suites = [unittest.makeSuite(t) for t in testcases]
return unittest.TestSuite(suites)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -819,6 +819,9 @@ Documentation
Tests Tests
----- -----
- Issue #22060: test_ctypes has been somewhat cleaned up and simplified; it
now uses unittest test discovery to find its tests.
- Issue #22104: regrtest.py no longer holds a reference to the suite of tests - Issue #22104: regrtest.py no longer holds a reference to the suite of tests
loaded from test modules that don't define test_main(). loaded from test modules that don't define test_main().