Closes #22060: Merge with 3.4
This commit is contained in:
commit
d630e0070f
|
@ -1,216 +1,14 @@
|
|||
import os, sys, unittest, getopt, time
|
||||
import os
|
||||
import unittest
|
||||
from test import support
|
||||
|
||||
use_resources = []
|
||||
|
||||
import ctypes
|
||||
# skip tests if _ctypes was not built
|
||||
ctypes = support.import_module('ctypes')
|
||||
ctypes_symbols = dir(ctypes)
|
||||
|
||||
def need_symbol(name):
|
||||
return unittest.skipUnless(name in ctypes_symbols,
|
||||
'{!r} is required'.format(name))
|
||||
|
||||
|
||||
class ResourceDenied(unittest.SkipTest):
|
||||
"""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
|
||||
def load_tests(*args):
|
||||
return support.load_package_tests(os.path.dirname(__file__), *args)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from ctypes.test import load_tests
|
||||
import unittest
|
||||
|
||||
unittest.main()
|
|
@ -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))
|
|
@ -1,60 +1,58 @@
|
|||
import unittest
|
||||
import os
|
||||
import sys
|
||||
import test.support
|
||||
from ctypes import *
|
||||
from ctypes.util import find_library
|
||||
from ctypes.test import is_resource_enabled
|
||||
|
||||
if sys.platform == "win32":
|
||||
lib_gl = find_library("OpenGL32")
|
||||
lib_glu = find_library("Glu32")
|
||||
lib_gle = None
|
||||
elif sys.platform == "darwin":
|
||||
lib_gl = lib_glu = find_library("OpenGL")
|
||||
lib_gle = None
|
||||
else:
|
||||
lib_gl = find_library("GL")
|
||||
lib_glu = find_library("GLU")
|
||||
lib_gle = find_library("gle")
|
||||
|
||||
## print, for debugging
|
||||
if is_resource_enabled("printing"):
|
||||
if lib_gl or lib_glu or lib_gle:
|
||||
print("OpenGL libraries:")
|
||||
for item in (("GL", lib_gl),
|
||||
("GLU", lib_glu),
|
||||
("gle", lib_gle)):
|
||||
print("\t", item)
|
||||
|
||||
|
||||
# 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
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
lib_gl = lib_glu = lib_gle = None
|
||||
if sys.platform == "win32":
|
||||
lib_gl = find_library("OpenGL32")
|
||||
lib_glu = find_library("Glu32")
|
||||
elif sys.platform == "darwin":
|
||||
lib_gl = lib_glu = find_library("OpenGL")
|
||||
else:
|
||||
lib_gl = find_library("GL")
|
||||
lib_glu = find_library("GLU")
|
||||
lib_gle = find_library("gle")
|
||||
|
||||
## print, for debugging
|
||||
if test.support.verbose:
|
||||
print("OpenGL libraries:")
|
||||
for item in (("GL", lib_gl),
|
||||
("GLU", lib_glu),
|
||||
("gle", lib_gle)):
|
||||
print("\t", item)
|
||||
|
||||
cls.gl = cls.glu = cls.gle = None
|
||||
if lib_gl:
|
||||
self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
|
||||
cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
|
||||
if lib_glu:
|
||||
self.glu = CDLL(lib_glu, RTLD_GLOBAL)
|
||||
cls.glu = CDLL(lib_glu, RTLD_GLOBAL)
|
||||
if lib_gle:
|
||||
try:
|
||||
self.gle = CDLL(lib_gle)
|
||||
cls.gle = CDLL(lib_gle)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
@unittest.skipUnless(lib_gl, 'lib_gl not available')
|
||||
def test_gl(self):
|
||||
if self.gl:
|
||||
self.gl.glClearIndex
|
||||
if self.gl is None:
|
||||
self.skipTest('lib_gl not available')
|
||||
self.gl.glClearIndex
|
||||
|
||||
@unittest.skipUnless(lib_glu, 'lib_glu not available')
|
||||
def test_glu(self):
|
||||
if self.glu:
|
||||
self.glu.gluBeginCurve
|
||||
if self.glu is None:
|
||||
self.skipTest('lib_glu not available')
|
||||
self.glu.gluBeginCurve
|
||||
|
||||
@unittest.skipUnless(lib_gle, 'lib_gle not available')
|
||||
def test_gle(self):
|
||||
if self.gle:
|
||||
self.gle.gleGetJoinStyle
|
||||
if self.gle is None:
|
||||
self.skipTest('lib_gle not available')
|
||||
self.gle.gleGetJoinStyle
|
||||
|
||||
# On platforms where the default shared library suffix is '.so',
|
||||
# at least some libraries can be loaded as attributes of the cdll
|
||||
|
|
|
@ -1,37 +1,42 @@
|
|||
from ctypes import *
|
||||
import sys, unittest
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import test.support
|
||||
from ctypes.util import find_library
|
||||
from ctypes.test import is_resource_enabled
|
||||
|
||||
libc_name = None
|
||||
if os.name == "nt":
|
||||
libc_name = find_library("c")
|
||||
elif os.name == "ce":
|
||||
libc_name = "coredll"
|
||||
elif sys.platform == "cygwin":
|
||||
libc_name = "cygwin1.dll"
|
||||
else:
|
||||
libc_name = find_library("c")
|
||||
|
||||
if is_resource_enabled("printing"):
|
||||
print("libc_name is", libc_name)
|
||||
def setUpModule():
|
||||
global libc_name
|
||||
if os.name == "nt":
|
||||
libc_name = find_library("c")
|
||||
elif os.name == "ce":
|
||||
libc_name = "coredll"
|
||||
elif sys.platform == "cygwin":
|
||||
libc_name = "cygwin1.dll"
|
||||
else:
|
||||
libc_name = find_library("c")
|
||||
|
||||
if test.support.verbose:
|
||||
print("libc_name is", libc_name)
|
||||
|
||||
class LoaderTest(unittest.TestCase):
|
||||
|
||||
unknowndll = "xxrandomnamexx"
|
||||
|
||||
@unittest.skipUnless(libc_name is not None, 'could not find libc')
|
||||
def test_load(self):
|
||||
if libc_name is None:
|
||||
self.skipTest('could not find libc')
|
||||
CDLL(libc_name)
|
||||
CDLL(os.path.basename(libc_name))
|
||||
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):
|
||||
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")
|
||||
# linux uses version, libc 9 should not exist
|
||||
self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9")
|
||||
|
@ -48,7 +53,7 @@ class LoaderTest(unittest.TestCase):
|
|||
'test specific to Windows (NT/CE)')
|
||||
def test_load_library(self):
|
||||
self.assertIsNotNone(libc_name)
|
||||
if is_resource_enabled("printing"):
|
||||
if test.support.verbose:
|
||||
print(find_library("kernel32"))
|
||||
print(find_library("user32"))
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from ctypes import *
|
||||
import unittest, sys
|
||||
from test import support
|
||||
from ctypes.test import requires
|
||||
|
||||
################################################################
|
||||
# This section should be moved into ctypes\__init__.py, when it's ready.
|
||||
|
@ -39,12 +38,8 @@ class PythonAPITestCase(unittest.TestCase):
|
|||
del pyob
|
||||
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
|
||||
def test_PyLong_Long(self):
|
||||
requires("refcount")
|
||||
ref42 = grc(42)
|
||||
pythonapi.PyLong_FromLong.restype = py_object
|
||||
self.assertEqual(pythonapi.PyLong_FromLong(42), 42)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# Windows specific tests
|
||||
|
||||
from ctypes import *
|
||||
from ctypes.test import requires
|
||||
import unittest, sys
|
||||
from test import support
|
||||
|
||||
|
@ -42,7 +41,6 @@ class FunctionCallTestCase(unittest.TestCase):
|
|||
@unittest.skipIf(sys.executable.endswith('_d.exe'),
|
||||
"SEH not enabled in debug builds")
|
||||
def test_SEH(self):
|
||||
requires("SEH")
|
||||
# Call functions with invalid arguments, and make sure
|
||||
# that access violations are trapped and raise an
|
||||
# exception.
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
import unittest
|
||||
|
||||
from test.support import import_module
|
||||
|
||||
# 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)
|
||||
from ctypes.test import load_tests
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -819,6 +819,9 @@ Documentation
|
|||
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
|
||||
loaded from test modules that don't define test_main().
|
||||
|
||||
|
|
Loading…
Reference in New Issue