summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorZachary Ware <zachary.ware@gmail.com>2014-08-08 18:32:16 (GMT)
committerZachary Ware <zachary.ware@gmail.com>2014-08-08 18:32:16 (GMT)
commit5a794c16d98a12f75b728ff902c410f10f93770f (patch)
treed9f29c5e59cf7fed90e5bf09d8b06f6bc3eda690 /Lib
parent79a1ffde9b3ae4b7dccdf2a64c6fc7cb7c243211 (diff)
downloadcpython-5a794c16d98a12f75b728ff902c410f10f93770f.zip
cpython-5a794c16d98a12f75b728ff902c410f10f93770f.tar.gz
cpython-5a794c16d98a12f75b728ff902c410f10f93770f.tar.bz2
Issue #22060: Clean up/simplify test_ctypes, use test discovery
Diffstat (limited to 'Lib')
-rw-r--r--Lib/ctypes/test/__init__.py216
-rw-r--r--Lib/ctypes/test/__main__.py4
-rw-r--r--Lib/ctypes/test/runtests.py19
-rw-r--r--Lib/ctypes/test/test_find.py72
-rw-r--r--Lib/ctypes/test/test_loading.py43
-rw-r--r--Lib/ctypes/test/test_python_api.py5
-rw-r--r--Lib/ctypes/test/test_win32.py2
-rw-r--r--Lib/test/test_ctypes.py12
8 files changed, 71 insertions, 302 deletions
diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py
index aef54c3..26a70b7 100644
--- a/Lib/ctypes/test/__init__.py
+++ b/Lib/ctypes/test/__init__.py
@@ -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)
diff --git a/Lib/ctypes/test/__main__.py b/Lib/ctypes/test/__main__.py
new file mode 100644
index 0000000..362a9ec
--- /dev/null
+++ b/Lib/ctypes/test/__main__.py
@@ -0,0 +1,4 @@
+from ctypes.test import load_tests
+import unittest
+
+unittest.main()
diff --git a/Lib/ctypes/test/runtests.py b/Lib/ctypes/test/runtests.py
deleted file mode 100644
index b7a2b26..0000000
--- a/Lib/ctypes/test/runtests.py
+++ /dev/null
@@ -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))
diff --git a/Lib/ctypes/test/test_find.py b/Lib/ctypes/test/test_find.py
index d838099..d8cd8ad 100644
--- a/Lib/ctypes/test/test_find.py
+++ b/Lib/ctypes/test/test_find.py
@@ -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
diff --git a/Lib/ctypes/test/test_loading.py b/Lib/ctypes/test/test_loading.py
index 3ab07c1..4fb8964 100644
--- a/Lib/ctypes/test/test_loading.py
+++ b/Lib/ctypes/test/test_loading.py
@@ -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"))
diff --git a/Lib/ctypes/test/test_python_api.py b/Lib/ctypes/test/test_python_api.py
index 0bd2f4c..9c13746 100644
--- a/Lib/ctypes/test/test_python_api.py
+++ b/Lib/ctypes/test/test_python_api.py
@@ -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)
diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py
index fcd2163..93573dd 100644
--- a/Lib/ctypes/test/test_win32.py
+++ b/Lib/ctypes/test/test_win32.py
@@ -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.
diff --git a/Lib/test/test_ctypes.py b/Lib/test/test_ctypes.py
index 496355e..53964ca 100644
--- a/Lib/test/test_ctypes.py
+++ b/Lib/test/test_ctypes.py
@@ -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()