mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-111165: Move test running code from test.support to libregrtest (GH-111166)
Remove no longer used functions run_unittest() and run_doctest() from the test.support module.
This commit is contained in:
parent
a8a89fcd1f
commit
f6a45a03d0
12 changed files with 266 additions and 342 deletions
|
@ -508,34 +508,6 @@ The :mod:`test.support` module defines the following functions:
|
||||||
Define match patterns on test filenames and test method names for filtering tests.
|
Define match patterns on test filenames and test method names for filtering tests.
|
||||||
|
|
||||||
|
|
||||||
.. function:: run_unittest(*classes)
|
|
||||||
|
|
||||||
Execute :class:`unittest.TestCase` subclasses passed to the function. The
|
|
||||||
function scans the classes for methods starting with the prefix ``test_``
|
|
||||||
and executes the tests individually.
|
|
||||||
|
|
||||||
It is also legal to pass strings as parameters; these should be keys in
|
|
||||||
``sys.modules``. Each associated module will be scanned by
|
|
||||||
``unittest.TestLoader.loadTestsFromModule()``. This is usually seen in the
|
|
||||||
following :func:`test_main` function::
|
|
||||||
|
|
||||||
def test_main():
|
|
||||||
support.run_unittest(__name__)
|
|
||||||
|
|
||||||
This will run all tests defined in the named module.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: run_doctest(module, verbosity=None, optionflags=0)
|
|
||||||
|
|
||||||
Run :func:`doctest.testmod` on the given *module*. Return
|
|
||||||
``(failure_count, test_count)``.
|
|
||||||
|
|
||||||
If *verbosity* is ``None``, :func:`doctest.testmod` is run with verbosity
|
|
||||||
set to :data:`verbose`. Otherwise, it is run with verbosity set to
|
|
||||||
``None``. *optionflags* is passed as ``optionflags`` to
|
|
||||||
:func:`doctest.testmod`.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: get_pagesize()
|
.. function:: get_pagesize()
|
||||||
|
|
||||||
Get size of a page in bytes.
|
Get size of a page in bytes.
|
||||||
|
|
72
Lib/test/libregrtest/filter.py
Normal file
72
Lib/test/libregrtest/filter.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import itertools
|
||||||
|
import operator
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
# By default, don't filter tests
|
||||||
|
_test_matchers = ()
|
||||||
|
_test_patterns = ()
|
||||||
|
|
||||||
|
|
||||||
|
def match_test(test):
|
||||||
|
# Function used by support.run_unittest() and regrtest --list-cases
|
||||||
|
result = False
|
||||||
|
for matcher, result in reversed(_test_matchers):
|
||||||
|
if matcher(test.id()):
|
||||||
|
return result
|
||||||
|
return not result
|
||||||
|
|
||||||
|
|
||||||
|
def _is_full_match_test(pattern):
|
||||||
|
# If a pattern contains at least one dot, it's considered
|
||||||
|
# as a full test identifier.
|
||||||
|
# Example: 'test.test_os.FileTests.test_access'.
|
||||||
|
#
|
||||||
|
# ignore patterns which contain fnmatch patterns: '*', '?', '[...]'
|
||||||
|
# or '[!...]'. For example, ignore 'test_access*'.
|
||||||
|
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))
|
||||||
|
|
||||||
|
|
||||||
|
def set_match_tests(patterns):
|
||||||
|
global _test_matchers, _test_patterns
|
||||||
|
|
||||||
|
if not patterns:
|
||||||
|
_test_matchers = ()
|
||||||
|
_test_patterns = ()
|
||||||
|
else:
|
||||||
|
itemgetter = operator.itemgetter
|
||||||
|
patterns = tuple(patterns)
|
||||||
|
if patterns != _test_patterns:
|
||||||
|
_test_matchers = [
|
||||||
|
(_compile_match_function(map(itemgetter(0), it)), result)
|
||||||
|
for result, it in itertools.groupby(patterns, itemgetter(1))
|
||||||
|
]
|
||||||
|
_test_patterns = patterns
|
||||||
|
|
||||||
|
|
||||||
|
def _compile_match_function(patterns):
|
||||||
|
patterns = list(patterns)
|
||||||
|
|
||||||
|
if all(map(_is_full_match_test, patterns)):
|
||||||
|
# Simple case: all patterns are full test identifier.
|
||||||
|
# The test.bisect_cmd utility only uses such full test identifiers.
|
||||||
|
return set(patterns).__contains__
|
||||||
|
else:
|
||||||
|
import fnmatch
|
||||||
|
regex = '|'.join(map(fnmatch.translate, patterns))
|
||||||
|
# The search *is* case sensitive on purpose:
|
||||||
|
# don't use flags=re.IGNORECASE
|
||||||
|
regex_match = re.compile(regex).match
|
||||||
|
|
||||||
|
def match_test_regex(test_id, regex_match=regex_match):
|
||||||
|
if regex_match(test_id):
|
||||||
|
# The regex matches the whole identifier, for example
|
||||||
|
# 'test.test_os.FileTests.test_access'.
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Try to match parts of the test identifier.
|
||||||
|
# For example, split 'test.test_os.FileTests.test_access'
|
||||||
|
# into: 'test', 'test_os', 'FileTests' and 'test_access'.
|
||||||
|
return any(map(regex_match, test_id.split(".")))
|
||||||
|
|
||||||
|
return match_test_regex
|
|
@ -4,6 +4,7 @@ import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
|
from .filter import match_test, set_match_tests
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, TestName, TestTuple, TestList, TestFilter,
|
StrPath, TestName, TestTuple, TestList, TestFilter,
|
||||||
abs_module_name, count, printlist)
|
abs_module_name, count, printlist)
|
||||||
|
@ -79,14 +80,14 @@ def _list_cases(suite):
|
||||||
if isinstance(test, unittest.TestSuite):
|
if isinstance(test, unittest.TestSuite):
|
||||||
_list_cases(test)
|
_list_cases(test)
|
||||||
elif isinstance(test, unittest.TestCase):
|
elif isinstance(test, unittest.TestCase):
|
||||||
if support.match_test(test):
|
if match_test(test):
|
||||||
print(test.id())
|
print(test.id())
|
||||||
|
|
||||||
def list_cases(tests: TestTuple, *,
|
def list_cases(tests: TestTuple, *,
|
||||||
match_tests: TestFilter | None = None,
|
match_tests: TestFilter | None = None,
|
||||||
test_dir: StrPath | None = None):
|
test_dir: StrPath | None = None):
|
||||||
support.verbose = False
|
support.verbose = False
|
||||||
support.set_match_tests(match_tests)
|
set_match_tests(match_tests)
|
||||||
|
|
||||||
skipped = []
|
skipped = []
|
||||||
for test_name in tests:
|
for test_name in tests:
|
||||||
|
|
|
@ -2,13 +2,35 @@ import dataclasses
|
||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from test.support import TestStats
|
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrJSON, TestName, FilterTuple,
|
StrJSON, TestName, FilterTuple,
|
||||||
format_duration, normalize_test_name, print_warning)
|
format_duration, normalize_test_name, print_warning)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(slots=True)
|
||||||
|
class TestStats:
|
||||||
|
tests_run: int = 0
|
||||||
|
failures: int = 0
|
||||||
|
skipped: int = 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_unittest(result):
|
||||||
|
return TestStats(result.testsRun,
|
||||||
|
len(result.failures),
|
||||||
|
len(result.skipped))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_doctest(results):
|
||||||
|
return TestStats(results.attempted,
|
||||||
|
results.failed,
|
||||||
|
results.skipped)
|
||||||
|
|
||||||
|
def accumulate(self, stats):
|
||||||
|
self.tests_run += stats.tests_run
|
||||||
|
self.failures += stats.failures
|
||||||
|
self.skipped += stats.skipped
|
||||||
|
|
||||||
|
|
||||||
# Avoid enum.Enum to reduce the number of imports when tests are run
|
# Avoid enum.Enum to reduce the number of imports when tests are run
|
||||||
class State:
|
class State:
|
||||||
PASSED = "PASSED"
|
PASSED = "PASSED"
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
from test.support import TestStats
|
|
||||||
|
|
||||||
from .runtests import RunTests
|
from .runtests import RunTests
|
||||||
from .result import State, TestResult
|
from .result import State, TestResult, TestStats
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, TestName, TestTuple, TestList, FilterDict,
|
StrPath, TestName, TestTuple, TestList, FilterDict,
|
||||||
printlist, count, format_duration)
|
printlist, count, format_duration)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII
|
from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII
|
||||||
|
|
||||||
|
from .filter import set_match_tests
|
||||||
from .runtests import RunTests
|
from .runtests import RunTests
|
||||||
from .utils import (
|
from .utils import (
|
||||||
setup_unraisable_hook, setup_threading_excepthook, fix_umask,
|
setup_unraisable_hook, setup_threading_excepthook, fix_umask,
|
||||||
|
@ -92,11 +93,11 @@ def setup_tests(runtests: RunTests):
|
||||||
support.PGO = runtests.pgo
|
support.PGO = runtests.pgo
|
||||||
support.PGO_EXTENDED = runtests.pgo_extended
|
support.PGO_EXTENDED = runtests.pgo_extended
|
||||||
|
|
||||||
support.set_match_tests(runtests.match_tests)
|
set_match_tests(runtests.match_tests)
|
||||||
|
|
||||||
if runtests.use_junit:
|
if runtests.use_junit:
|
||||||
support.junit_xml_list = []
|
support.junit_xml_list = []
|
||||||
from test.support.testresult import RegressionTestResult
|
from .testresult import RegressionTestResult
|
||||||
RegressionTestResult.USE_XML = True
|
RegressionTestResult.USE_XML = True
|
||||||
else:
|
else:
|
||||||
support.junit_xml_list = None
|
support.junit_xml_list = None
|
||||||
|
|
|
@ -9,13 +9,14 @@ import traceback
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import TestStats
|
|
||||||
from test.support import threading_helper
|
from test.support import threading_helper
|
||||||
|
|
||||||
from .result import State, TestResult
|
from .filter import match_test
|
||||||
|
from .result import State, TestResult, TestStats
|
||||||
from .runtests import RunTests
|
from .runtests import RunTests
|
||||||
from .save_env import saved_test_environment
|
from .save_env import saved_test_environment
|
||||||
from .setup import setup_tests
|
from .setup import setup_tests
|
||||||
|
from .testresult import get_test_runner
|
||||||
from .utils import (
|
from .utils import (
|
||||||
TestName,
|
TestName,
|
||||||
clear_caches, remove_testfn, abs_module_name, print_warning)
|
clear_caches, remove_testfn, abs_module_name, print_warning)
|
||||||
|
@ -33,7 +34,47 @@ def run_unittest(test_mod):
|
||||||
print(error, file=sys.stderr)
|
print(error, file=sys.stderr)
|
||||||
if loader.errors:
|
if loader.errors:
|
||||||
raise Exception("errors while loading tests")
|
raise Exception("errors while loading tests")
|
||||||
return support.run_unittest(tests)
|
_filter_suite(tests, match_test)
|
||||||
|
return _run_suite(tests)
|
||||||
|
|
||||||
|
def _filter_suite(suite, pred):
|
||||||
|
"""Recursively filter test cases in a suite based on a predicate."""
|
||||||
|
newtests = []
|
||||||
|
for test in suite._tests:
|
||||||
|
if isinstance(test, unittest.TestSuite):
|
||||||
|
_filter_suite(test, pred)
|
||||||
|
newtests.append(test)
|
||||||
|
else:
|
||||||
|
if pred(test):
|
||||||
|
newtests.append(test)
|
||||||
|
suite._tests = newtests
|
||||||
|
|
||||||
|
def _run_suite(suite):
|
||||||
|
"""Run tests from a unittest.TestSuite-derived class."""
|
||||||
|
runner = get_test_runner(sys.stdout,
|
||||||
|
verbosity=support.verbose,
|
||||||
|
capture_output=(support.junit_xml_list is not None))
|
||||||
|
|
||||||
|
result = runner.run(suite)
|
||||||
|
|
||||||
|
if support.junit_xml_list is not None:
|
||||||
|
support.junit_xml_list.append(result.get_xml_element())
|
||||||
|
|
||||||
|
if not result.testsRun and not result.skipped and not result.errors:
|
||||||
|
raise support.TestDidNotRun
|
||||||
|
if not result.wasSuccessful():
|
||||||
|
stats = TestStats.from_unittest(result)
|
||||||
|
if len(result.errors) == 1 and not result.failures:
|
||||||
|
err = result.errors[0][1]
|
||||||
|
elif len(result.failures) == 1 and not result.errors:
|
||||||
|
err = result.failures[0][1]
|
||||||
|
else:
|
||||||
|
err = "multiple errors occurred"
|
||||||
|
if not verbose: err += "; run in verbose mode for details"
|
||||||
|
errors = [(str(tc), exc_str) for tc, exc_str in result.errors]
|
||||||
|
failures = [(str(tc), exc_str) for tc, exc_str in result.failures]
|
||||||
|
raise support.TestFailedWithDetails(err, errors, failures, stats=stats)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None:
|
def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None:
|
||||||
|
|
|
@ -6,10 +6,8 @@ if __name__ != 'test.support':
|
||||||
import contextlib
|
import contextlib
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
|
||||||
import getpass
|
import getpass
|
||||||
import _opcode
|
import _opcode
|
||||||
import operator
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import stat
|
import stat
|
||||||
|
@ -21,8 +19,6 @@ import types
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from .testresult import get_test_runner
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# globals
|
# globals
|
||||||
|
@ -36,7 +32,6 @@ __all__ = [
|
||||||
"is_resource_enabled", "requires", "requires_freebsd_version",
|
"is_resource_enabled", "requires", "requires_freebsd_version",
|
||||||
"requires_linux_version", "requires_mac_ver",
|
"requires_linux_version", "requires_mac_ver",
|
||||||
"check_syntax_error",
|
"check_syntax_error",
|
||||||
"run_unittest", "run_doctest",
|
|
||||||
"requires_gzip", "requires_bz2", "requires_lzma",
|
"requires_gzip", "requires_bz2", "requires_lzma",
|
||||||
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
|
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
|
||||||
"requires_IEEE_754", "requires_zlib",
|
"requires_IEEE_754", "requires_zlib",
|
||||||
|
@ -1120,156 +1115,6 @@ def requires_specialization(test):
|
||||||
return unittest.skipUnless(
|
return unittest.skipUnless(
|
||||||
_opcode.ENABLE_SPECIALIZATION, "requires specialization")(test)
|
_opcode.ENABLE_SPECIALIZATION, "requires specialization")(test)
|
||||||
|
|
||||||
def _filter_suite(suite, pred):
|
|
||||||
"""Recursively filter test cases in a suite based on a predicate."""
|
|
||||||
newtests = []
|
|
||||||
for test in suite._tests:
|
|
||||||
if isinstance(test, unittest.TestSuite):
|
|
||||||
_filter_suite(test, pred)
|
|
||||||
newtests.append(test)
|
|
||||||
else:
|
|
||||||
if pred(test):
|
|
||||||
newtests.append(test)
|
|
||||||
suite._tests = newtests
|
|
||||||
|
|
||||||
@dataclasses.dataclass(slots=True)
|
|
||||||
class TestStats:
|
|
||||||
tests_run: int = 0
|
|
||||||
failures: int = 0
|
|
||||||
skipped: int = 0
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_unittest(result):
|
|
||||||
return TestStats(result.testsRun,
|
|
||||||
len(result.failures),
|
|
||||||
len(result.skipped))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_doctest(results):
|
|
||||||
return TestStats(results.attempted,
|
|
||||||
results.failed,
|
|
||||||
results.skipped)
|
|
||||||
|
|
||||||
def accumulate(self, stats):
|
|
||||||
self.tests_run += stats.tests_run
|
|
||||||
self.failures += stats.failures
|
|
||||||
self.skipped += stats.skipped
|
|
||||||
|
|
||||||
|
|
||||||
def _run_suite(suite):
|
|
||||||
"""Run tests from a unittest.TestSuite-derived class."""
|
|
||||||
runner = get_test_runner(sys.stdout,
|
|
||||||
verbosity=verbose,
|
|
||||||
capture_output=(junit_xml_list is not None))
|
|
||||||
|
|
||||||
result = runner.run(suite)
|
|
||||||
|
|
||||||
if junit_xml_list is not None:
|
|
||||||
junit_xml_list.append(result.get_xml_element())
|
|
||||||
|
|
||||||
if not result.testsRun and not result.skipped and not result.errors:
|
|
||||||
raise TestDidNotRun
|
|
||||||
if not result.wasSuccessful():
|
|
||||||
stats = TestStats.from_unittest(result)
|
|
||||||
if len(result.errors) == 1 and not result.failures:
|
|
||||||
err = result.errors[0][1]
|
|
||||||
elif len(result.failures) == 1 and not result.errors:
|
|
||||||
err = result.failures[0][1]
|
|
||||||
else:
|
|
||||||
err = "multiple errors occurred"
|
|
||||||
if not verbose: err += "; run in verbose mode for details"
|
|
||||||
errors = [(str(tc), exc_str) for tc, exc_str in result.errors]
|
|
||||||
failures = [(str(tc), exc_str) for tc, exc_str in result.failures]
|
|
||||||
raise TestFailedWithDetails(err, errors, failures, stats=stats)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
# By default, don't filter tests
|
|
||||||
_test_matchers = ()
|
|
||||||
_test_patterns = ()
|
|
||||||
|
|
||||||
|
|
||||||
def match_test(test):
|
|
||||||
# Function used by support.run_unittest() and regrtest --list-cases
|
|
||||||
result = False
|
|
||||||
for matcher, result in reversed(_test_matchers):
|
|
||||||
if matcher(test.id()):
|
|
||||||
return result
|
|
||||||
return not result
|
|
||||||
|
|
||||||
|
|
||||||
def _is_full_match_test(pattern):
|
|
||||||
# If a pattern contains at least one dot, it's considered
|
|
||||||
# as a full test identifier.
|
|
||||||
# Example: 'test.test_os.FileTests.test_access'.
|
|
||||||
#
|
|
||||||
# ignore patterns which contain fnmatch patterns: '*', '?', '[...]'
|
|
||||||
# or '[!...]'. For example, ignore 'test_access*'.
|
|
||||||
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))
|
|
||||||
|
|
||||||
|
|
||||||
def set_match_tests(patterns):
|
|
||||||
global _test_matchers, _test_patterns
|
|
||||||
|
|
||||||
if not patterns:
|
|
||||||
_test_matchers = ()
|
|
||||||
_test_patterns = ()
|
|
||||||
else:
|
|
||||||
itemgetter = operator.itemgetter
|
|
||||||
patterns = tuple(patterns)
|
|
||||||
if patterns != _test_patterns:
|
|
||||||
_test_matchers = [
|
|
||||||
(_compile_match_function(map(itemgetter(0), it)), result)
|
|
||||||
for result, it in itertools.groupby(patterns, itemgetter(1))
|
|
||||||
]
|
|
||||||
_test_patterns = patterns
|
|
||||||
|
|
||||||
|
|
||||||
def _compile_match_function(patterns):
|
|
||||||
patterns = list(patterns)
|
|
||||||
|
|
||||||
if all(map(_is_full_match_test, patterns)):
|
|
||||||
# Simple case: all patterns are full test identifier.
|
|
||||||
# The test.bisect_cmd utility only uses such full test identifiers.
|
|
||||||
return set(patterns).__contains__
|
|
||||||
else:
|
|
||||||
import fnmatch
|
|
||||||
regex = '|'.join(map(fnmatch.translate, patterns))
|
|
||||||
# The search *is* case sensitive on purpose:
|
|
||||||
# don't use flags=re.IGNORECASE
|
|
||||||
regex_match = re.compile(regex).match
|
|
||||||
|
|
||||||
def match_test_regex(test_id, regex_match=regex_match):
|
|
||||||
if regex_match(test_id):
|
|
||||||
# The regex matches the whole identifier, for example
|
|
||||||
# 'test.test_os.FileTests.test_access'.
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# Try to match parts of the test identifier.
|
|
||||||
# For example, split 'test.test_os.FileTests.test_access'
|
|
||||||
# into: 'test', 'test_os', 'FileTests' and 'test_access'.
|
|
||||||
return any(map(regex_match, test_id.split(".")))
|
|
||||||
|
|
||||||
return match_test_regex
|
|
||||||
|
|
||||||
|
|
||||||
def run_unittest(*classes):
|
|
||||||
"""Run tests from unittest.TestCase-derived classes."""
|
|
||||||
valid_types = (unittest.TestSuite, unittest.TestCase)
|
|
||||||
loader = unittest.TestLoader()
|
|
||||||
suite = unittest.TestSuite()
|
|
||||||
for cls in classes:
|
|
||||||
if isinstance(cls, str):
|
|
||||||
if cls in sys.modules:
|
|
||||||
suite.addTest(loader.loadTestsFromModule(sys.modules[cls]))
|
|
||||||
else:
|
|
||||||
raise ValueError("str arguments must be keys in sys.modules")
|
|
||||||
elif isinstance(cls, valid_types):
|
|
||||||
suite.addTest(cls)
|
|
||||||
else:
|
|
||||||
suite.addTest(loader.loadTestsFromTestCase(cls))
|
|
||||||
_filter_suite(suite, match_test)
|
|
||||||
return _run_suite(suite)
|
|
||||||
|
|
||||||
#=======================================================================
|
#=======================================================================
|
||||||
# Check for the presence of docstrings.
|
# Check for the presence of docstrings.
|
||||||
|
@ -1291,38 +1136,6 @@ requires_docstrings = unittest.skipUnless(HAVE_DOCSTRINGS,
|
||||||
"test requires docstrings")
|
"test requires docstrings")
|
||||||
|
|
||||||
|
|
||||||
#=======================================================================
|
|
||||||
# doctest driver.
|
|
||||||
|
|
||||||
def run_doctest(module, verbosity=None, optionflags=0):
|
|
||||||
"""Run doctest on the given module. Return (#failures, #tests).
|
|
||||||
|
|
||||||
If optional argument verbosity is not specified (or is None), pass
|
|
||||||
support's belief about verbosity on to doctest. Else doctest's
|
|
||||||
usual behavior is used (it searches sys.argv for -v).
|
|
||||||
"""
|
|
||||||
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
if verbosity is None:
|
|
||||||
verbosity = verbose
|
|
||||||
else:
|
|
||||||
verbosity = None
|
|
||||||
|
|
||||||
results = doctest.testmod(module,
|
|
||||||
verbose=verbosity,
|
|
||||||
optionflags=optionflags)
|
|
||||||
if results.failed:
|
|
||||||
stats = TestStats.from_doctest(results)
|
|
||||||
raise TestFailed(f"{results.failed} of {results.attempted} "
|
|
||||||
f"doctests failed",
|
|
||||||
stats=stats)
|
|
||||||
if verbose:
|
|
||||||
print('doctest (%s) ... %d tests with zero failures' %
|
|
||||||
(module.__name__, results.attempted))
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
#=======================================================================
|
#=======================================================================
|
||||||
# Support for saving and restoring the imported modules.
|
# Support for saving and restoring the imported modules.
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,13 @@ import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper, TestStats, without_optimizer
|
from test.support import os_helper, without_optimizer
|
||||||
from test.libregrtest import cmdline
|
from test.libregrtest import cmdline
|
||||||
from test.libregrtest import main
|
from test.libregrtest import main
|
||||||
from test.libregrtest import setup
|
from test.libregrtest import setup
|
||||||
from test.libregrtest import utils
|
from test.libregrtest import utils
|
||||||
|
from test.libregrtest.filter import set_match_tests, match_test
|
||||||
|
from test.libregrtest.result import TestStats
|
||||||
from test.libregrtest.utils import normalize_test_name
|
from test.libregrtest.utils import normalize_test_name
|
||||||
|
|
||||||
if not support.has_subprocess_support:
|
if not support.has_subprocess_support:
|
||||||
|
@ -2182,6 +2184,120 @@ class TestUtils(unittest.TestCase):
|
||||||
format_resources((*ALL_RESOURCES, "tzdata")),
|
format_resources((*ALL_RESOURCES, "tzdata")),
|
||||||
'resources: all,tzdata')
|
'resources: all,tzdata')
|
||||||
|
|
||||||
|
def test_match_test(self):
|
||||||
|
class Test:
|
||||||
|
def __init__(self, test_id):
|
||||||
|
self.test_id = test_id
|
||||||
|
|
||||||
|
def id(self):
|
||||||
|
return self.test_id
|
||||||
|
|
||||||
|
test_access = Test('test.test_os.FileTests.test_access')
|
||||||
|
test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir')
|
||||||
|
test_copy = Test('test.test_shutil.TestCopy.test_copy')
|
||||||
|
|
||||||
|
# Test acceptance
|
||||||
|
with support.swap_attr(support, '_test_matchers', ()):
|
||||||
|
# match all
|
||||||
|
set_match_tests([])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
|
||||||
|
# match all using None
|
||||||
|
set_match_tests(None)
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
|
||||||
|
# match the full test identifier
|
||||||
|
set_match_tests([(test_access.id(), True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
|
||||||
|
# match the module name
|
||||||
|
set_match_tests([('test_os', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
self.assertFalse(match_test(test_copy))
|
||||||
|
|
||||||
|
# Test '*' pattern
|
||||||
|
set_match_tests([('test_*', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
|
||||||
|
# Test case sensitivity
|
||||||
|
set_match_tests([('filetests', True)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
set_match_tests([('FileTests', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
|
||||||
|
# Test pattern containing '.' and a '*' metacharacter
|
||||||
|
set_match_tests([('*test_os.*.test_*', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
self.assertFalse(match_test(test_copy))
|
||||||
|
|
||||||
|
# Multiple patterns
|
||||||
|
set_match_tests([(test_access.id(), True), (test_chdir.id(), True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
self.assertFalse(match_test(test_copy))
|
||||||
|
|
||||||
|
set_match_tests([('test_access', True), ('DONTMATCH', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
|
||||||
|
# Test rejection
|
||||||
|
with support.swap_attr(support, '_test_matchers', ()):
|
||||||
|
# match the full test identifier
|
||||||
|
set_match_tests([(test_access.id(), False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
|
||||||
|
# match the module name
|
||||||
|
set_match_tests([('test_os', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
self.assertTrue(match_test(test_copy))
|
||||||
|
|
||||||
|
# Test '*' pattern
|
||||||
|
set_match_tests([('test_*', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
|
||||||
|
# Test case sensitivity
|
||||||
|
set_match_tests([('filetests', False)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
set_match_tests([('FileTests', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
|
||||||
|
# Test pattern containing '.' and a '*' metacharacter
|
||||||
|
set_match_tests([('*test_os.*.test_*', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
self.assertTrue(match_test(test_copy))
|
||||||
|
|
||||||
|
# Multiple patterns
|
||||||
|
set_match_tests([(test_access.id(), False), (test_chdir.id(), False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
self.assertTrue(match_test(test_copy))
|
||||||
|
|
||||||
|
set_match_tests([('test_access', False), ('DONTMATCH', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
|
||||||
|
# Test mixed filters
|
||||||
|
with support.swap_attr(support, '_test_matchers', ()):
|
||||||
|
set_match_tests([('*test_os', False), ('test_access', True)])
|
||||||
|
self.assertTrue(match_test(test_access))
|
||||||
|
self.assertFalse(match_test(test_chdir))
|
||||||
|
self.assertTrue(match_test(test_copy))
|
||||||
|
|
||||||
|
set_match_tests([('*test_os', True), ('test_access', False)])
|
||||||
|
self.assertFalse(match_test(test_access))
|
||||||
|
self.assertTrue(match_test(test_chdir))
|
||||||
|
self.assertFalse(match_test(test_copy))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -547,120 +547,6 @@ class TestSupport(unittest.TestCase):
|
||||||
with self.subTest(opts=opts):
|
with self.subTest(opts=opts):
|
||||||
self.check_options(opts, 'optim_args_from_interpreter_flags')
|
self.check_options(opts, 'optim_args_from_interpreter_flags')
|
||||||
|
|
||||||
def test_match_test(self):
|
|
||||||
class Test:
|
|
||||||
def __init__(self, test_id):
|
|
||||||
self.test_id = test_id
|
|
||||||
|
|
||||||
def id(self):
|
|
||||||
return self.test_id
|
|
||||||
|
|
||||||
test_access = Test('test.test_os.FileTests.test_access')
|
|
||||||
test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir')
|
|
||||||
test_copy = Test('test.test_shutil.TestCopy.test_copy')
|
|
||||||
|
|
||||||
# Test acceptance
|
|
||||||
with support.swap_attr(support, '_test_matchers', ()):
|
|
||||||
# match all
|
|
||||||
support.set_match_tests([])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match all using None
|
|
||||||
support.set_match_tests(None)
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match the full test identifier
|
|
||||||
support.set_match_tests([(test_access.id(), True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match the module name
|
|
||||||
support.set_match_tests([('test_os', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
self.assertFalse(support.match_test(test_copy))
|
|
||||||
|
|
||||||
# Test '*' pattern
|
|
||||||
support.set_match_tests([('test_*', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# Test case sensitivity
|
|
||||||
support.set_match_tests([('filetests', True)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
support.set_match_tests([('FileTests', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
|
|
||||||
# Test pattern containing '.' and a '*' metacharacter
|
|
||||||
support.set_match_tests([('*test_os.*.test_*', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
self.assertFalse(support.match_test(test_copy))
|
|
||||||
|
|
||||||
# Multiple patterns
|
|
||||||
support.set_match_tests([(test_access.id(), True), (test_chdir.id(), True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
self.assertFalse(support.match_test(test_copy))
|
|
||||||
|
|
||||||
support.set_match_tests([('test_access', True), ('DONTMATCH', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# Test rejection
|
|
||||||
with support.swap_attr(support, '_test_matchers', ()):
|
|
||||||
# match the full test identifier
|
|
||||||
support.set_match_tests([(test_access.id(), False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match the module name
|
|
||||||
support.set_match_tests([('test_os', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
self.assertTrue(support.match_test(test_copy))
|
|
||||||
|
|
||||||
# Test '*' pattern
|
|
||||||
support.set_match_tests([('test_*', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# Test case sensitivity
|
|
||||||
support.set_match_tests([('filetests', False)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
support.set_match_tests([('FileTests', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
|
|
||||||
# Test pattern containing '.' and a '*' metacharacter
|
|
||||||
support.set_match_tests([('*test_os.*.test_*', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
self.assertTrue(support.match_test(test_copy))
|
|
||||||
|
|
||||||
# Multiple patterns
|
|
||||||
support.set_match_tests([(test_access.id(), False), (test_chdir.id(), False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
self.assertTrue(support.match_test(test_copy))
|
|
||||||
|
|
||||||
support.set_match_tests([('test_access', False), ('DONTMATCH', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# Test mixed filters
|
|
||||||
with support.swap_attr(support, '_test_matchers', ()):
|
|
||||||
support.set_match_tests([('*test_os', False), ('test_access', True)])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
|
||||||
self.assertTrue(support.match_test(test_copy))
|
|
||||||
|
|
||||||
support.set_match_tests([('*test_os', True), ('test_access', False)])
|
|
||||||
self.assertFalse(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
self.assertFalse(support.match_test(test_copy))
|
|
||||||
|
|
||||||
@unittest.skipIf(support.is_emscripten, "Unstable in Emscripten")
|
@unittest.skipIf(support.is_emscripten, "Unstable in Emscripten")
|
||||||
@unittest.skipIf(support.is_wasi, "Unavailable on WASI")
|
@unittest.skipIf(support.is_wasi, "Unavailable on WASI")
|
||||||
def test_fd_count(self):
|
def test_fd_count(self):
|
||||||
|
@ -861,7 +747,6 @@ class TestSupport(unittest.TestCase):
|
||||||
# precisionbigmemtest
|
# precisionbigmemtest
|
||||||
# bigaddrspacetest
|
# bigaddrspacetest
|
||||||
# requires_resource
|
# requires_resource
|
||||||
# run_doctest
|
|
||||||
# threading_cleanup
|
# threading_cleanup
|
||||||
# reap_threads
|
# reap_threads
|
||||||
# can_symlink
|
# can_symlink
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Remove no longer used functions ``run_unittest()`` and ``run_doctest()``
|
||||||
|
from the :mod:`test.support` module.
|
Loading…
Add table
Add a link
Reference in a new issue