Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,12 @@ def _list_cases(self, suite):
if isinstance(test, unittest.TestSuite):
self._list_cases(test)
elif isinstance(test, unittest.TestCase):
if support._match_test(test):
if support.match_test(test):
print(test.id())

def list_cases(self):
support.verbose = False
support.match_tests = self.ns.match_tests
support.set_match_tests(self.ns.match_tests)

for test in self.selected:
abstest = get_abs_module(self.ns, test)
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/libregrtest/runtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def runtest(ns, test):
if use_timeout:
faulthandler.dump_traceback_later(ns.timeout, exit=True)
try:
support.match_tests = ns.match_tests
support.set_match_tests(ns.match_tests)
if ns.failfast:
support.failfast = True
if output_on_failure:
Expand Down
69 changes: 57 additions & 12 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ def get_attribute(obj, name):
# small sizes, to make sure they work.)
real_max_memuse = 0
failfast = False
match_tests = None

# _original_stdout is meant to hold stdout at the time regrtest began.
# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever.
Expand Down Expand Up @@ -1897,21 +1896,67 @@ def _run_suite(suite):
raise TestFailed(err)


def _match_test(test):
global match_tests
# By default, don't filter tests
_match_test_func = None
_match_test_patterns = None

if match_tests is None:

def match_test(test):
# Function used by support.run_unittest() and regrtest --list-cases
if _match_test_func is None:
return True
test_id = test.id()
else:
return _match_test_func(test.id())

for match_test in match_tests:
if fnmatch.fnmatchcase(test_id, match_test):
return True

for name in test_id.split("."):
if fnmatch.fnmatchcase(name, match_test):
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'.
#
# Reject patterns which contain fnmatch patterns: '*', '?', '[...]'
# or '[!...]'. For example, reject 'test_access*'.
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))


def set_match_tests(patterns):
global _match_test_func, _match_test_patterns

if patterns == _match_test_patterns:
# No change: no need to recompile patterns.
return

if not patterns:
func = None
# set_match_tests(None) behaves as set_match_tests(())
patterns = ()
elif all(map(_is_full_match_test, patterns)):
# Simple case: all patterns are full test identifier.
# The test.bisect utility only uses such full test identifiers.
func = set(patterns).__contains__
else:
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):
if regex_match(test_id):
# The regex matchs the whole identifier like
# 'test.test_os.FileTests.test_access'
return True
return False
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(".")))

func = match_test_regex

# Create a copy since patterns can be mutable and so modified later
_match_test_patterns = tuple(patterns)
_match_test_func = func



def run_unittest(*classes):
Expand All @@ -1928,7 +1973,7 @@ def run_unittest(*classes):
suite.addTest(cls)
else:
suite.addTest(unittest.makeSuite(cls))
_filter_suite(suite, _match_test)
_filter_suite(suite, match_test)
_run_suite(suite)

#=======================================================================
Expand Down
58 changes: 58 additions & 0 deletions Lib/test/test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,64 @@ def test_check__all__(self):

self.assertRaises(AssertionError, support.check__all__, self, unittest)

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')

with support.swap_attr(support, '_match_test_func', None):
# 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()])
self.assertTrue(support.match_test(test_access))
self.assertFalse(support.match_test(test_chdir))

# match the module name
support.set_match_tests(['test_os'])
self.assertTrue(support.match_test(test_access))
self.assertTrue(support.match_test(test_chdir))

# Test '*' pattern
support.set_match_tests(['test_*'])
self.assertTrue(support.match_test(test_access))
self.assertTrue(support.match_test(test_chdir))

# Test case sensitivity
support.set_match_tests(['filetests'])
self.assertFalse(support.match_test(test_access))
support.set_match_tests(['FileTests'])
self.assertTrue(support.match_test(test_access))

# Test pattern containing '.' and a '*' metacharacter
support.set_match_tests(['*test_os.*.test_*'])
self.assertTrue(support.match_test(test_access))
self.assertTrue(support.match_test(test_chdir))

# Multiple patterns
support.set_match_tests([test_access.id(), test_chdir.id()])
self.assertTrue(support.match_test(test_access))
self.assertTrue(support.match_test(test_chdir))

support.set_match_tests(['test_access', 'DONTMATCH'])
self.assertTrue(support.match_test(test_access))
self.assertFalse(support.match_test(test_chdir))


# XXX -follows a list of untested API
# make_legacy_pyc
# is_resource_enabled
Expand Down