mirror of
https://github.com/python/cpython.git
synced 2025-08-15 22:30:42 +00:00
[3.12] gh-110918: regrtest: allow to intermix --match and --ignore options (GH-110919) (GH-111167)
Test case matching patterns specified by options --match, --ignore,
--matchfile and --ignorefile are now tested in the order of
specification, and the last match determines whether the test case be run
or ignored.
(cherry picked from commit 9a1fe09622
)
This commit is contained in:
parent
6a5ff93654
commit
1ea93024d4
12 changed files with 128 additions and 143 deletions
|
@ -161,8 +161,7 @@ class Namespace(argparse.Namespace):
|
||||||
self.forever = False
|
self.forever = False
|
||||||
self.header = False
|
self.header = False
|
||||||
self.failfast = False
|
self.failfast = False
|
||||||
self.match_tests = None
|
self.match_tests = []
|
||||||
self.ignore_tests = None
|
|
||||||
self.pgo = False
|
self.pgo = False
|
||||||
self.pgo_extended = False
|
self.pgo_extended = False
|
||||||
self.worker_json = None
|
self.worker_json = None
|
||||||
|
@ -183,6 +182,20 @@ class _ArgParser(argparse.ArgumentParser):
|
||||||
super().error(message + "\nPass -h or --help for complete help.")
|
super().error(message + "\nPass -h or --help for complete help.")
|
||||||
|
|
||||||
|
|
||||||
|
class FilterAction(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, value, option_string=None):
|
||||||
|
items = getattr(namespace, self.dest)
|
||||||
|
items.append((value, self.const))
|
||||||
|
|
||||||
|
|
||||||
|
class FromFileFilterAction(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, value, option_string=None):
|
||||||
|
items = getattr(namespace, self.dest)
|
||||||
|
with open(value, encoding='utf-8') as fp:
|
||||||
|
for line in fp:
|
||||||
|
items.append((line.strip(), self.const))
|
||||||
|
|
||||||
|
|
||||||
def _create_parser():
|
def _create_parser():
|
||||||
# Set prog to prevent the uninformative "__main__.py" from displaying in
|
# Set prog to prevent the uninformative "__main__.py" from displaying in
|
||||||
# error messages when using "python -m test ...".
|
# error messages when using "python -m test ...".
|
||||||
|
@ -192,6 +205,7 @@ def _create_parser():
|
||||||
epilog=EPILOG,
|
epilog=EPILOG,
|
||||||
add_help=False,
|
add_help=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser.set_defaults(match_tests=[])
|
||||||
|
|
||||||
# Arguments with this clause added to its help are described further in
|
# Arguments with this clause added to its help are described further in
|
||||||
# the epilog's "Additional option details" section.
|
# the epilog's "Additional option details" section.
|
||||||
|
@ -251,17 +265,19 @@ def _create_parser():
|
||||||
help='single step through a set of tests.' +
|
help='single step through a set of tests.' +
|
||||||
more_details)
|
more_details)
|
||||||
group.add_argument('-m', '--match', metavar='PAT',
|
group.add_argument('-m', '--match', metavar='PAT',
|
||||||
dest='match_tests', action='append',
|
dest='match_tests', action=FilterAction, const=True,
|
||||||
help='match test cases and methods with glob pattern PAT')
|
help='match test cases and methods with glob pattern PAT')
|
||||||
group.add_argument('-i', '--ignore', metavar='PAT',
|
group.add_argument('-i', '--ignore', metavar='PAT',
|
||||||
dest='ignore_tests', action='append',
|
dest='match_tests', action=FilterAction, const=False,
|
||||||
help='ignore test cases and methods with glob pattern PAT')
|
help='ignore test cases and methods with glob pattern PAT')
|
||||||
group.add_argument('--matchfile', metavar='FILENAME',
|
group.add_argument('--matchfile', metavar='FILENAME',
|
||||||
dest='match_filename',
|
dest='match_tests',
|
||||||
|
action=FromFileFilterAction, const=True,
|
||||||
help='similar to --match but get patterns from a '
|
help='similar to --match but get patterns from a '
|
||||||
'text file, one pattern per line')
|
'text file, one pattern per line')
|
||||||
group.add_argument('--ignorefile', metavar='FILENAME',
|
group.add_argument('--ignorefile', metavar='FILENAME',
|
||||||
dest='ignore_filename',
|
dest='match_tests',
|
||||||
|
action=FromFileFilterAction, const=False,
|
||||||
help='similar to --matchfile but it receives patterns '
|
help='similar to --matchfile but it receives patterns '
|
||||||
'from text file to ignore')
|
'from text file to ignore')
|
||||||
group.add_argument('-G', '--failfast', action='store_true',
|
group.add_argument('-G', '--failfast', action='store_true',
|
||||||
|
@ -483,18 +499,6 @@ def _parse_args(args, **kwargs):
|
||||||
print("WARNING: Disable --verbose3 because it's incompatible with "
|
print("WARNING: Disable --verbose3 because it's incompatible with "
|
||||||
"--huntrleaks: see http://bugs.python.org/issue27103",
|
"--huntrleaks: see http://bugs.python.org/issue27103",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
if ns.match_filename:
|
|
||||||
if ns.match_tests is None:
|
|
||||||
ns.match_tests = []
|
|
||||||
with open(ns.match_filename) as fp:
|
|
||||||
for line in fp:
|
|
||||||
ns.match_tests.append(line.strip())
|
|
||||||
if ns.ignore_filename:
|
|
||||||
if ns.ignore_tests is None:
|
|
||||||
ns.ignore_tests = []
|
|
||||||
with open(ns.ignore_filename) as fp:
|
|
||||||
for line in fp:
|
|
||||||
ns.ignore_tests.append(line.strip())
|
|
||||||
if ns.forever:
|
if ns.forever:
|
||||||
# --forever implies --failfast
|
# --forever implies --failfast
|
||||||
ns.failfast = True
|
ns.failfast = True
|
||||||
|
|
|
@ -5,7 +5,7 @@ import unittest
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, TestName, TestTuple, TestList, FilterTuple,
|
StrPath, TestName, TestTuple, TestList, TestFilter,
|
||||||
abs_module_name, count, printlist)
|
abs_module_name, count, printlist)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,11 +83,10 @@ def _list_cases(suite):
|
||||||
print(test.id())
|
print(test.id())
|
||||||
|
|
||||||
def list_cases(tests: TestTuple, *,
|
def list_cases(tests: TestTuple, *,
|
||||||
match_tests: FilterTuple | None = None,
|
match_tests: TestFilter | None = None,
|
||||||
ignore_tests: FilterTuple | None = None,
|
|
||||||
test_dir: StrPath | None = None):
|
test_dir: StrPath | None = None):
|
||||||
support.verbose = False
|
support.verbose = False
|
||||||
support.set_match_tests(match_tests, ignore_tests)
|
support.set_match_tests(match_tests)
|
||||||
|
|
||||||
skipped = []
|
skipped = []
|
||||||
for test_name in tests:
|
for test_name in tests:
|
||||||
|
|
|
@ -19,7 +19,7 @@ from .runtests import RunTests, HuntRefleak
|
||||||
from .setup import setup_process, setup_test_dir
|
from .setup import setup_process, setup_test_dir
|
||||||
from .single import run_single_test, PROGRESS_MIN_TIME
|
from .single import run_single_test, PROGRESS_MIN_TIME
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, StrJSON, TestName, TestList, TestTuple, FilterTuple,
|
StrPath, StrJSON, TestName, TestList, TestTuple, TestFilter,
|
||||||
strip_py_suffix, count, format_duration,
|
strip_py_suffix, count, format_duration,
|
||||||
printlist, get_temp_dir, get_work_dir, exit_timeout,
|
printlist, get_temp_dir, get_work_dir, exit_timeout,
|
||||||
display_header, cleanup_temp_dir, print_warning,
|
display_header, cleanup_temp_dir, print_warning,
|
||||||
|
@ -78,14 +78,7 @@ class Regrtest:
|
||||||
and ns._add_python_opts)
|
and ns._add_python_opts)
|
||||||
|
|
||||||
# Select tests
|
# Select tests
|
||||||
if ns.match_tests:
|
self.match_tests: TestFilter = ns.match_tests
|
||||||
self.match_tests: FilterTuple | None = tuple(ns.match_tests)
|
|
||||||
else:
|
|
||||||
self.match_tests = None
|
|
||||||
if ns.ignore_tests:
|
|
||||||
self.ignore_tests: FilterTuple | None = tuple(ns.ignore_tests)
|
|
||||||
else:
|
|
||||||
self.ignore_tests = None
|
|
||||||
self.exclude: bool = ns.exclude
|
self.exclude: bool = ns.exclude
|
||||||
self.fromfile: StrPath | None = ns.fromfile
|
self.fromfile: StrPath | None = ns.fromfile
|
||||||
self.starting_test: TestName | None = ns.start
|
self.starting_test: TestName | None = ns.start
|
||||||
|
@ -389,7 +382,7 @@ class Regrtest:
|
||||||
|
|
||||||
def display_summary(self):
|
def display_summary(self):
|
||||||
duration = time.perf_counter() - self.logger.start_time
|
duration = time.perf_counter() - self.logger.start_time
|
||||||
filtered = bool(self.match_tests) or bool(self.ignore_tests)
|
filtered = bool(self.match_tests)
|
||||||
|
|
||||||
# Total duration
|
# Total duration
|
||||||
print()
|
print()
|
||||||
|
@ -407,7 +400,6 @@ class Regrtest:
|
||||||
fail_fast=self.fail_fast,
|
fail_fast=self.fail_fast,
|
||||||
fail_env_changed=self.fail_env_changed,
|
fail_env_changed=self.fail_env_changed,
|
||||||
match_tests=self.match_tests,
|
match_tests=self.match_tests,
|
||||||
ignore_tests=self.ignore_tests,
|
|
||||||
match_tests_dict=None,
|
match_tests_dict=None,
|
||||||
rerun=False,
|
rerun=False,
|
||||||
forever=self.forever,
|
forever=self.forever,
|
||||||
|
@ -660,7 +652,6 @@ class Regrtest:
|
||||||
elif self.want_list_cases:
|
elif self.want_list_cases:
|
||||||
list_cases(selected,
|
list_cases(selected,
|
||||||
match_tests=self.match_tests,
|
match_tests=self.match_tests,
|
||||||
ignore_tests=self.ignore_tests,
|
|
||||||
test_dir=self.test_dir)
|
test_dir=self.test_dir)
|
||||||
else:
|
else:
|
||||||
exitcode = self.run_tests(selected, tests)
|
exitcode = self.run_tests(selected, tests)
|
||||||
|
|
|
@ -261,7 +261,7 @@ class WorkerThread(threading.Thread):
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if match_tests:
|
if match_tests:
|
||||||
kwargs['match_tests'] = match_tests
|
kwargs['match_tests'] = [(test, True) for test in match_tests]
|
||||||
if self.runtests.output_on_failure:
|
if self.runtests.output_on_failure:
|
||||||
kwargs['verbose'] = True
|
kwargs['verbose'] = True
|
||||||
kwargs['output_on_failure'] = False
|
kwargs['output_on_failure'] = False
|
||||||
|
|
|
@ -8,7 +8,7 @@ from typing import Any
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, StrJSON, TestTuple, FilterTuple, FilterDict)
|
StrPath, StrJSON, TestTuple, TestFilter, FilterTuple, FilterDict)
|
||||||
|
|
||||||
|
|
||||||
class JsonFileType:
|
class JsonFileType:
|
||||||
|
@ -72,8 +72,7 @@ class RunTests:
|
||||||
tests: TestTuple
|
tests: TestTuple
|
||||||
fail_fast: bool
|
fail_fast: bool
|
||||||
fail_env_changed: bool
|
fail_env_changed: bool
|
||||||
match_tests: FilterTuple | None
|
match_tests: TestFilter
|
||||||
ignore_tests: FilterTuple | None
|
|
||||||
match_tests_dict: FilterDict | None
|
match_tests_dict: FilterDict | None
|
||||||
rerun: bool
|
rerun: bool
|
||||||
forever: bool
|
forever: bool
|
||||||
|
|
|
@ -92,7 +92,7 @@ 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, runtests.ignore_tests)
|
support.set_match_tests(runtests.match_tests)
|
||||||
|
|
||||||
if runtests.use_junit:
|
if runtests.use_junit:
|
||||||
support.junit_xml_list = []
|
support.junit_xml_list = []
|
||||||
|
|
|
@ -52,6 +52,7 @@ TestTuple = tuple[TestName, ...]
|
||||||
TestList = list[TestName]
|
TestList = list[TestName]
|
||||||
# --match and --ignore options: list of patterns
|
# --match and --ignore options: list of patterns
|
||||||
# ('*' joker character can be used)
|
# ('*' joker character can be used)
|
||||||
|
TestFilter = list[tuple[TestName, bool]]
|
||||||
FilterTuple = tuple[TestName, ...]
|
FilterTuple = tuple[TestName, ...]
|
||||||
FilterDict = dict[TestName, FilterTuple]
|
FilterDict = dict[TestName, FilterTuple]
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .setup import setup_process, setup_test_dir
|
||||||
from .runtests import RunTests, JsonFile, JsonFileType
|
from .runtests import RunTests, JsonFile, JsonFileType
|
||||||
from .single import run_single_test
|
from .single import run_single_test
|
||||||
from .utils import (
|
from .utils import (
|
||||||
StrPath, StrJSON, FilterTuple,
|
StrPath, StrJSON, TestFilter,
|
||||||
get_temp_dir, get_work_dir, exit_timeout)
|
get_temp_dir, get_work_dir, exit_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ def create_worker_process(runtests: RunTests, output_fd: int,
|
||||||
def worker_process(worker_json: StrJSON) -> NoReturn:
|
def worker_process(worker_json: StrJSON) -> NoReturn:
|
||||||
runtests = RunTests.from_json(worker_json)
|
runtests = RunTests.from_json(worker_json)
|
||||||
test_name = runtests.tests[0]
|
test_name = runtests.tests[0]
|
||||||
match_tests: FilterTuple | None = runtests.match_tests
|
match_tests: TestFilter = runtests.match_tests
|
||||||
json_file: JsonFile = runtests.json_file
|
json_file: JsonFile = runtests.json_file
|
||||||
|
|
||||||
setup_test_dir(runtests.test_dir)
|
setup_test_dir(runtests.test_dir)
|
||||||
|
@ -81,7 +81,7 @@ def worker_process(worker_json: StrJSON) -> NoReturn:
|
||||||
|
|
||||||
if runtests.rerun:
|
if runtests.rerun:
|
||||||
if match_tests:
|
if match_tests:
|
||||||
matching = "matching: " + ", ".join(match_tests)
|
matching = "matching: " + ", ".join(pattern for pattern, result in match_tests if result)
|
||||||
print(f"Re-running {test_name} in verbose mode ({matching})", flush=True)
|
print(f"Re-running {test_name} in verbose mode ({matching})", flush=True)
|
||||||
else:
|
else:
|
||||||
print(f"Re-running {test_name} in verbose mode", flush=True)
|
print(f"Re-running {test_name} in verbose mode", flush=True)
|
||||||
|
|
|
@ -6,8 +6,10 @@ 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
|
||||||
|
@ -1194,18 +1196,17 @@ def _run_suite(suite):
|
||||||
|
|
||||||
|
|
||||||
# By default, don't filter tests
|
# By default, don't filter tests
|
||||||
_match_test_func = None
|
_test_matchers = ()
|
||||||
|
_test_patterns = ()
|
||||||
_accept_test_patterns = None
|
|
||||||
_ignore_test_patterns = None
|
|
||||||
|
|
||||||
|
|
||||||
def match_test(test):
|
def match_test(test):
|
||||||
# Function used by support.run_unittest() and regrtest --list-cases
|
# Function used by support.run_unittest() and regrtest --list-cases
|
||||||
if _match_test_func is None:
|
result = False
|
||||||
return True
|
for matcher, result in reversed(_test_matchers):
|
||||||
else:
|
if matcher(test.id()):
|
||||||
return _match_test_func(test.id())
|
return result
|
||||||
|
return not result
|
||||||
|
|
||||||
|
|
||||||
def _is_full_match_test(pattern):
|
def _is_full_match_test(pattern):
|
||||||
|
@ -1218,47 +1219,30 @@ def _is_full_match_test(pattern):
|
||||||
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))
|
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))
|
||||||
|
|
||||||
|
|
||||||
def set_match_tests(accept_patterns=None, ignore_patterns=None):
|
def set_match_tests(patterns):
|
||||||
global _match_test_func, _accept_test_patterns, _ignore_test_patterns
|
global _test_matchers, _test_patterns
|
||||||
|
|
||||||
if accept_patterns is None:
|
if not patterns:
|
||||||
accept_patterns = ()
|
_test_matchers = ()
|
||||||
if ignore_patterns is None:
|
_test_patterns = ()
|
||||||
ignore_patterns = ()
|
else:
|
||||||
|
itemgetter = operator.itemgetter
|
||||||
accept_func = ignore_func = None
|
patterns = tuple(patterns)
|
||||||
|
if patterns != _test_patterns:
|
||||||
if accept_patterns != _accept_test_patterns:
|
_test_matchers = [
|
||||||
accept_patterns, accept_func = _compile_match_function(accept_patterns)
|
(_compile_match_function(map(itemgetter(0), it)), result)
|
||||||
if ignore_patterns != _ignore_test_patterns:
|
for result, it in itertools.groupby(patterns, itemgetter(1))
|
||||||
ignore_patterns, ignore_func = _compile_match_function(ignore_patterns)
|
]
|
||||||
|
_test_patterns = patterns
|
||||||
# Create a copy since patterns can be mutable and so modified later
|
|
||||||
_accept_test_patterns = tuple(accept_patterns)
|
|
||||||
_ignore_test_patterns = tuple(ignore_patterns)
|
|
||||||
|
|
||||||
if accept_func is not None or ignore_func is not None:
|
|
||||||
def match_function(test_id):
|
|
||||||
accept = True
|
|
||||||
ignore = False
|
|
||||||
if accept_func:
|
|
||||||
accept = accept_func(test_id)
|
|
||||||
if ignore_func:
|
|
||||||
ignore = ignore_func(test_id)
|
|
||||||
return accept and not ignore
|
|
||||||
|
|
||||||
_match_test_func = match_function
|
|
||||||
|
|
||||||
|
|
||||||
def _compile_match_function(patterns):
|
def _compile_match_function(patterns):
|
||||||
if not patterns:
|
patterns = list(patterns)
|
||||||
func = None
|
|
||||||
# set_match_tests(None) behaves as set_match_tests(())
|
if all(map(_is_full_match_test, patterns)):
|
||||||
patterns = ()
|
|
||||||
elif all(map(_is_full_match_test, patterns)):
|
|
||||||
# Simple case: all patterns are full test identifier.
|
# Simple case: all patterns are full test identifier.
|
||||||
# The test.bisect_cmd utility only uses such full test identifiers.
|
# The test.bisect_cmd utility only uses such full test identifiers.
|
||||||
func = set(patterns).__contains__
|
return set(patterns).__contains__
|
||||||
else:
|
else:
|
||||||
import fnmatch
|
import fnmatch
|
||||||
regex = '|'.join(map(fnmatch.translate, patterns))
|
regex = '|'.join(map(fnmatch.translate, patterns))
|
||||||
|
@ -1266,7 +1250,7 @@ def _compile_match_function(patterns):
|
||||||
# don't use flags=re.IGNORECASE
|
# don't use flags=re.IGNORECASE
|
||||||
regex_match = re.compile(regex).match
|
regex_match = re.compile(regex).match
|
||||||
|
|
||||||
def match_test_regex(test_id):
|
def match_test_regex(test_id, regex_match=regex_match):
|
||||||
if regex_match(test_id):
|
if regex_match(test_id):
|
||||||
# The regex matches the whole identifier, for example
|
# The regex matches the whole identifier, for example
|
||||||
# 'test.test_os.FileTests.test_access'.
|
# 'test.test_os.FileTests.test_access'.
|
||||||
|
@ -1277,9 +1261,7 @@ def _compile_match_function(patterns):
|
||||||
# into: 'test', 'test_os', 'FileTests' and 'test_access'.
|
# into: 'test', 'test_os', 'FileTests' and 'test_access'.
|
||||||
return any(map(regex_match, test_id.split(".")))
|
return any(map(regex_match, test_id.split(".")))
|
||||||
|
|
||||||
func = match_test_regex
|
return match_test_regex
|
||||||
|
|
||||||
return patterns, func
|
|
||||||
|
|
||||||
|
|
||||||
def run_unittest(*classes):
|
def run_unittest(*classes):
|
||||||
|
|
|
@ -192,34 +192,27 @@ class ParseArgsTestCase(unittest.TestCase):
|
||||||
self.assertTrue(ns.single)
|
self.assertTrue(ns.single)
|
||||||
self.checkError([opt, '-f', 'foo'], "don't go together")
|
self.checkError([opt, '-f', 'foo'], "don't go together")
|
||||||
|
|
||||||
def test_ignore(self):
|
|
||||||
for opt in '-i', '--ignore':
|
|
||||||
with self.subTest(opt=opt):
|
|
||||||
ns = self.parse_args([opt, 'pattern'])
|
|
||||||
self.assertEqual(ns.ignore_tests, ['pattern'])
|
|
||||||
self.checkError([opt], 'expected one argument')
|
|
||||||
|
|
||||||
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
|
||||||
with open(os_helper.TESTFN, "w") as fp:
|
|
||||||
print('matchfile1', file=fp)
|
|
||||||
print('matchfile2', file=fp)
|
|
||||||
|
|
||||||
filename = os.path.abspath(os_helper.TESTFN)
|
|
||||||
ns = self.parse_args(['-m', 'match',
|
|
||||||
'--ignorefile', filename])
|
|
||||||
self.assertEqual(ns.ignore_tests,
|
|
||||||
['matchfile1', 'matchfile2'])
|
|
||||||
|
|
||||||
def test_match(self):
|
def test_match(self):
|
||||||
for opt in '-m', '--match':
|
for opt in '-m', '--match':
|
||||||
with self.subTest(opt=opt):
|
with self.subTest(opt=opt):
|
||||||
ns = self.parse_args([opt, 'pattern'])
|
ns = self.parse_args([opt, 'pattern'])
|
||||||
self.assertEqual(ns.match_tests, ['pattern'])
|
self.assertEqual(ns.match_tests, [('pattern', True)])
|
||||||
self.checkError([opt], 'expected one argument')
|
self.checkError([opt], 'expected one argument')
|
||||||
|
|
||||||
ns = self.parse_args(['-m', 'pattern1',
|
for opt in '-i', '--ignore':
|
||||||
'-m', 'pattern2'])
|
with self.subTest(opt=opt):
|
||||||
self.assertEqual(ns.match_tests, ['pattern1', 'pattern2'])
|
ns = self.parse_args([opt, 'pattern'])
|
||||||
|
self.assertEqual(ns.match_tests, [('pattern', False)])
|
||||||
|
self.checkError([opt], 'expected one argument')
|
||||||
|
|
||||||
|
ns = self.parse_args(['-m', 'pattern1', '-m', 'pattern2'])
|
||||||
|
self.assertEqual(ns.match_tests, [('pattern1', True), ('pattern2', True)])
|
||||||
|
|
||||||
|
ns = self.parse_args(['-m', 'pattern1', '-i', 'pattern2'])
|
||||||
|
self.assertEqual(ns.match_tests, [('pattern1', True), ('pattern2', False)])
|
||||||
|
|
||||||
|
ns = self.parse_args(['-i', 'pattern1', '-m', 'pattern2'])
|
||||||
|
self.assertEqual(ns.match_tests, [('pattern1', False), ('pattern2', True)])
|
||||||
|
|
||||||
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
||||||
with open(os_helper.TESTFN, "w") as fp:
|
with open(os_helper.TESTFN, "w") as fp:
|
||||||
|
@ -227,10 +220,13 @@ class ParseArgsTestCase(unittest.TestCase):
|
||||||
print('matchfile2', file=fp)
|
print('matchfile2', file=fp)
|
||||||
|
|
||||||
filename = os.path.abspath(os_helper.TESTFN)
|
filename = os.path.abspath(os_helper.TESTFN)
|
||||||
ns = self.parse_args(['-m', 'match',
|
ns = self.parse_args(['-m', 'match', '--matchfile', filename])
|
||||||
'--matchfile', filename])
|
|
||||||
self.assertEqual(ns.match_tests,
|
self.assertEqual(ns.match_tests,
|
||||||
['match', 'matchfile1', 'matchfile2'])
|
[('match', True), ('matchfile1', True), ('matchfile2', True)])
|
||||||
|
|
||||||
|
ns = self.parse_args(['-i', 'match', '--ignorefile', filename])
|
||||||
|
self.assertEqual(ns.match_tests,
|
||||||
|
[('match', False), ('matchfile1', False), ('matchfile2', False)])
|
||||||
|
|
||||||
def test_failfast(self):
|
def test_failfast(self):
|
||||||
for opt in '-G', '--failfast':
|
for opt in '-G', '--failfast':
|
||||||
|
|
|
@ -560,101 +560,110 @@ class TestSupport(unittest.TestCase):
|
||||||
|
|
||||||
test_access = Test('test.test_os.FileTests.test_access')
|
test_access = Test('test.test_os.FileTests.test_access')
|
||||||
test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir')
|
test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir')
|
||||||
|
test_copy = Test('test.test_shutil.TestCopy.test_copy')
|
||||||
|
|
||||||
# Test acceptance
|
# Test acceptance
|
||||||
with support.swap_attr(support, '_match_test_func', None):
|
with support.swap_attr(support, '_test_matchers', ()):
|
||||||
# match all
|
# match all
|
||||||
support.set_match_tests([])
|
support.set_match_tests([])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
|
||||||
# match all using None
|
# match all using None
|
||||||
support.set_match_tests(None, None)
|
support.set_match_tests(None)
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
|
||||||
# match the full test identifier
|
# match the full test identifier
|
||||||
support.set_match_tests([test_access.id()], None)
|
support.set_match_tests([(test_access.id(), True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
|
||||||
# match the module name
|
# match the module name
|
||||||
support.set_match_tests(['test_os'], None)
|
support.set_match_tests([('test_os', True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
self.assertFalse(support.match_test(test_copy))
|
||||||
|
|
||||||
# Test '*' pattern
|
# Test '*' pattern
|
||||||
support.set_match_tests(['test_*'], None)
|
support.set_match_tests([('test_*', True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
|
||||||
# Test case sensitivity
|
# Test case sensitivity
|
||||||
support.set_match_tests(['filetests'], None)
|
support.set_match_tests([('filetests', True)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
support.set_match_tests(['FileTests'], None)
|
support.set_match_tests([('FileTests', True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
|
|
||||||
# Test pattern containing '.' and a '*' metacharacter
|
# Test pattern containing '.' and a '*' metacharacter
|
||||||
support.set_match_tests(['*test_os.*.test_*'], None)
|
support.set_match_tests([('*test_os.*.test_*', True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
self.assertFalse(support.match_test(test_copy))
|
||||||
|
|
||||||
# Multiple patterns
|
# Multiple patterns
|
||||||
support.set_match_tests([test_access.id(), test_chdir.id()], None)
|
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_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
self.assertFalse(support.match_test(test_copy))
|
||||||
|
|
||||||
support.set_match_tests(['test_access', 'DONTMATCH'], None)
|
support.set_match_tests([('test_access', True), ('DONTMATCH', True)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
|
||||||
# Test rejection
|
# Test rejection
|
||||||
with support.swap_attr(support, '_match_test_func', None):
|
with support.swap_attr(support, '_test_matchers', ()):
|
||||||
# match all
|
|
||||||
support.set_match_tests(ignore_patterns=[])
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match all using None
|
|
||||||
support.set_match_tests(None, None)
|
|
||||||
self.assertTrue(support.match_test(test_access))
|
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
|
||||||
|
|
||||||
# match the full test identifier
|
# match the full test identifier
|
||||||
support.set_match_tests(None, [test_access.id()])
|
support.set_match_tests([(test_access.id(), False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
self.assertTrue(support.match_test(test_chdir))
|
||||||
|
|
||||||
# match the module name
|
# match the module name
|
||||||
support.set_match_tests(None, ['test_os'])
|
support.set_match_tests([('test_os', False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
self.assertTrue(support.match_test(test_copy))
|
||||||
|
|
||||||
# Test '*' pattern
|
# Test '*' pattern
|
||||||
support.set_match_tests(None, ['test_*'])
|
support.set_match_tests([('test_*', False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
|
||||||
# Test case sensitivity
|
# Test case sensitivity
|
||||||
support.set_match_tests(None, ['filetests'])
|
support.set_match_tests([('filetests', False)])
|
||||||
self.assertTrue(support.match_test(test_access))
|
self.assertTrue(support.match_test(test_access))
|
||||||
support.set_match_tests(None, ['FileTests'])
|
support.set_match_tests([('FileTests', False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
|
|
||||||
# Test pattern containing '.' and a '*' metacharacter
|
# Test pattern containing '.' and a '*' metacharacter
|
||||||
support.set_match_tests(None, ['*test_os.*.test_*'])
|
support.set_match_tests([('*test_os.*.test_*', False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
self.assertTrue(support.match_test(test_copy))
|
||||||
|
|
||||||
# Multiple patterns
|
# Multiple patterns
|
||||||
support.set_match_tests(None, [test_access.id(), test_chdir.id()])
|
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_access))
|
||||||
self.assertFalse(support.match_test(test_chdir))
|
self.assertFalse(support.match_test(test_chdir))
|
||||||
|
self.assertTrue(support.match_test(test_copy))
|
||||||
|
|
||||||
support.set_match_tests(None, ['test_access', 'DONTMATCH'])
|
support.set_match_tests([('test_access', False), ('DONTMATCH', False)])
|
||||||
self.assertFalse(support.match_test(test_access))
|
self.assertFalse(support.match_test(test_access))
|
||||||
self.assertTrue(support.match_test(test_chdir))
|
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):
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Test case matching patterns specified by options ``--match``, ``--ignore``,
|
||||||
|
``--matchfile`` and ``--ignorefile`` are now tested in the order of
|
||||||
|
specification, and the last match determines whether the test case be run or
|
||||||
|
ignored.
|
Loading…
Add table
Add a link
Reference in a new issue