diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -50,6 +50,12 @@ Selecting tests --testdir DIR -- execute test files in the specified directory (instead of the Python stdlib test suite) +-k/--func-regex REGEX + -- only execute tests with function name matching REGEX (case + insensitive) +-K/--file-regex REGEX + -- only execute tests with file name matching REGEX (case + insensitive) Special runs @@ -278,13 +284,15 @@ def main(tests=None, testdir=None, verbo support.record_original_stdout(sys.stdout) try: - opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:FwWM:nj:', + opts, args = getopt.getopt(sys.argv[1:], + 'hvqxsSrf:lu:t:TD:NLR:FwWM:nj:k:K:', ['help', 'verbose', 'verbose2', 'verbose3', 'quiet', 'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', 'multiprocess=', 'coverage', 'slaveargs=', 'forever', 'debug', - 'start=', 'nowindows', 'header', 'testdir=', 'timeout=', 'wait']) + 'start=', 'nowindows', 'header', 'testdir=', 'timeout=', 'wait', + 'func-regex=', 'file-regex=']) except getopt.error as msg: usage(msg) @@ -295,6 +303,7 @@ def main(tests=None, testdir=None, verbo use_resources = [] debug = False start = None + file_regexes = [] for o, a in opts: if o in ('-h', '--help'): print(__doc__) @@ -426,6 +435,10 @@ def main(tests=None, testdir=None, verbo timeout = float(a) elif o == '--wait': input("Press any key to continue...") + elif o in ('-k', '--func-regex'): + support.run_unittest.regexes.append(re.compile(a, re.IGNORECASE)) + elif o in ('-K', '--file-regex'): + file_regexes.append(re.compile(a, re.IGNORECASE)) else: print(("No handler for option {}. Please report this as a bug " "at http://bugs.python.org.").format(o), file=sys.stderr) @@ -508,6 +521,9 @@ def main(tests=None, testdir=None, verbo alltests = findtests(testdir, stdtests, nottests) selected = tests or args or alltests + if file_regexes: + selected = [test for test in selected + if any(regex.search(test) for regex in file_regexes)] if single: selected = selected[:1] try: diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1217,19 +1217,28 @@ def _run_suite(suite): def run_unittest(*classes): """Run tests from unittest.TestCase-derived classes.""" + regexes = run_unittest.regexes + if regexes: + def filter_test(name): + return any(regex.search(name) for regex in regexes) + else: + filter_test = None valid_types = (unittest.TestSuite, unittest.TestCase) suite = unittest.TestSuite() for cls in classes: if isinstance(cls, str): if cls in sys.modules: - suite.addTest(unittest.findTestCases(sys.modules[cls])) + suite.addTest(unittest.findTestCases(sys.modules[cls], filter=filter_test)) else: raise ValueError("str arguments must be keys in sys.modules") elif isinstance(cls, valid_types): suite.addTest(cls) else: - suite.addTest(unittest.makeSuite(cls)) + suite.addTest(unittest.makeSuite(cls, filter=filter_test)) _run_suite(suite) +# List of regex objects used to filter the tests by their function name. +# An empty list means that all tests are used. +run_unittest.regexes = [] #======================================================================= diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -45,24 +45,26 @@ class TestLoader(object): suiteClass = suite.TestSuite _top_level_dir = None - def loadTestsFromTestCase(self, testCaseClass): + def loadTestsFromTestCase(self, testCaseClass, filter=None): """Return a suite of all tests cases contained in testCaseClass""" if issubclass(testCaseClass, suite.TestSuite): raise TypeError("Test cases should not be derived from TestSuite." \ " Maybe you meant to derive from TestCase?") testCaseNames = self.getTestCaseNames(testCaseClass) + if filter: + testCaseNames = [name for name in testCaseNames if filter(name)] if not testCaseNames and hasattr(testCaseClass, 'runTest'): testCaseNames = ['runTest'] loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) return loaded_suite - def loadTestsFromModule(self, module, use_load_tests=True): + def loadTestsFromModule(self, module, use_load_tests=True, filter=None): """Return a suite of all tests cases contained in the given module""" tests = [] for name in dir(module): obj = getattr(module, name) if isinstance(obj, type) and issubclass(obj, case.TestCase): - tests.append(self.loadTestsFromTestCase(obj)) + tests.append(self.loadTestsFromTestCase(obj, filter=filter)) load_tests = getattr(module, 'load_tests', None) tests = self.suiteClass(tests) @@ -311,11 +313,11 @@ def getTestCaseNames(testCaseClass, pref return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp, - suiteClass=suite.TestSuite): + suiteClass=suite.TestSuite, filter=None): return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase( - testCaseClass) + testCaseClass, filter=filter) def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp, - suiteClass=suite.TestSuite): - return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\ - module) + suiteClass=suite.TestSuite, filter=None): + loader = _makeLoader(prefix, sortUsing, suiteClass) + return loader.loadTestsFromModule(module, filter=filter)