add some useful utilities for skipping tests with unittest's new skipping ability

most significantly apply a modified portion of the patch from #4242 with
patches for skipping implementation details
This commit is contained in:
Benjamin Peterson 2009-03-26 19:58:18 +00:00
parent 0ad9b7727d
commit c3141a6e96
1 changed files with 67 additions and 1 deletions

View File

@ -8,6 +8,7 @@ import errno
import socket
import sys
import os
import platform
import shutil
import warnings
import unittest
@ -23,7 +24,8 @@ __all__ = ["Error", "TestFailed", "TestSkipped", "ResourceDenied", "import_modul
"captured_stdout", "TransientResource", "transient_internet",
"run_with_locale", "set_memlimit", "bigmemtest", "bigaddrspacetest",
"BasicTestRunner", "run_unittest", "run_doctest", "threading_setup",
"threading_cleanup", "reap_children"]
"threading_cleanup", "reap_children", "cpython_only",
"check_impl_detail"]
class Error(Exception):
"""Base class for regression test exceptions."""
@ -531,6 +533,21 @@ def captured_output(stream_name):
def captured_stdout():
return captured_output("stdout")
def gc_collect():
"""Force as many objects as possible to be collected.
In non-CPython implementations of Python, this is needed because timely
deallocation is not guaranteed by the garbage collector. (Even in CPython
this can be the case in case of reference cycles.) This means that __del__
methods may be called later than expected and weakrefs may remain alive for
longer than expected. This function tries its best to force all garbage
objects to disappear.
"""
import gc
gc.collect()
gc.collect()
gc.collect()
#=======================================================================
# Decorator for running a function in a different locale, correctly resetting
@ -682,6 +699,55 @@ class BasicTestRunner:
test(result)
return result
def _id(obj):
return obj
def requires_resource(resource):
if resource_is_enabled(resource):
return _id
else:
return unittest.skip("resource {0!r} is not enabled".format(resource))
def cpython_only(test):
"""
Decorator for tests only applicable on CPython.
"""
return impl_detail(cpython=True)(test)
def impl_detail(msg=None, **guards):
if check_impl_detail():
return _id
if msg is None:
guardnames, default = _parse_guards(guards)
if default:
msg = "implementation detail not available on {0}"
else:
msg = "implementation detail specific to {0}"
guardnames = sorted(guardnames.keys())
msg = msg.format(' or '.join(guardnames))
return unittest.skip(msg)
def _parse_guards(guards):
# Returns a tuple ({platform_name: run_me}, default_value)
if not guards:
return ({'cpython': True}, False)
is_true = guards.values()[0]
assert guards.values() == [is_true] * len(guards) # all True or all False
return (guards, not is_true)
# Use the following check to guard CPython's implementation-specific tests --
# or to run them only on the implementation(s) guarded by the arguments.
def check_impl_detail(**guards):
"""This function returns True or False depending on the host platform.
Examples:
if check_impl_detail(): # only on CPython (default)
if check_impl_detail(jython=True): # only on Jython
if check_impl_detail(cpython=False): # everywhere except on CPython
"""
guards, default = _parse_guards(guards)
return guards.get(platform.python_implementation().lower(), default)
def _run_suite(suite):
"""Run tests from a unittest.TestSuite-derived class."""