Fixed #32808 -- Prevented DiscoverRunner.build_suite() from mutating test loader patterns.

Thanks Chris Jerdonek for the report and reviews.
This commit is contained in:
Mariusz Felisiak 2021-06-03 08:59:37 +02:00 committed by GitHub
parent f0d0d29f03
commit 62e8f369c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 3 deletions

View File

@ -9,6 +9,7 @@ import pickle
import sys
import textwrap
import unittest
from contextlib import contextmanager
from importlib import import_module
from io import StringIO
@ -598,13 +599,24 @@ class DiscoverRunner:
setup_test_environment(debug=self.debug_mode)
unittest.installHandler()
@contextmanager
def load_with_patterns(self):
original_test_name_patterns = self.test_loader.testNamePatterns
self.test_loader.testNamePatterns = self.test_name_patterns
try:
yield
finally:
# Restore the original patterns.
self.test_loader.testNamePatterns = original_test_name_patterns
def load_tests_for_label(self, label, discover_kwargs):
label_as_path = os.path.abspath(label)
tests = None
# If a module, or "module.ClassName[.method_name]", just run those.
if not os.path.exists(label_as_path):
tests = self.test_loader.loadTestsFromName(label)
with self.load_with_patterns():
tests = self.test_loader.loadTestsFromName(label)
if tests.countTestCases():
return tests
# Try discovery if "label" is a package or directory.
@ -626,7 +638,8 @@ class DiscoverRunner:
if os.path.isdir(label_as_path) and not self.top_level:
kwargs['top_level_dir'] = find_top_level(label_as_path)
tests = self.test_loader.discover(start_dir=label, **kwargs)
with self.load_with_patterns():
tests = self.test_loader.discover(start_dir=label, **kwargs)
# Make unittest forget the top-level dir it calculated from this run,
# to support running tests from two different top-levels.
@ -636,7 +649,6 @@ class DiscoverRunner:
def build_suite(self, test_labels=None, extra_tests=None, **kwargs):
test_labels = test_labels or ['.']
extra_tests = extra_tests or []
self.test_loader.testNamePatterns = self.test_name_patterns
discover_kwargs = {}
if self.pattern is not None:

View File

@ -26,6 +26,16 @@ def change_cwd(directory):
os.chdir(old_cwd)
@contextmanager
def change_loader_patterns(patterns):
original_patterns = DiscoverRunner.test_loader.testNamePatterns
DiscoverRunner.test_loader.testNamePatterns = patterns
try:
yield
finally:
DiscoverRunner.test_loader.testNamePatterns = original_patterns
class DiscoverRunnerTests(SimpleTestCase):
@staticmethod
@ -122,6 +132,28 @@ class DiscoverRunnerTests(SimpleTestCase):
).build_suite(['test_runner_apps.simple'])
self.assertEqual(expected, self.get_test_methods_names(suite))
def test_loader_patterns_not_mutated(self):
runner = DiscoverRunner(test_name_patterns=['test_sample'], verbosity=0)
tests = [
('test_runner_apps.sample.tests', 1),
('test_runner_apps.sample.tests.Test.test_sample', 1),
('test_runner_apps.sample.empty', 0),
('test_runner_apps.sample.tests_sample.EmptyTestCase', 0),
]
for test_labels, tests_count in tests:
with self.subTest(test_labels=test_labels):
with change_loader_patterns(['UnittestCase1']):
count = runner.build_suite([test_labels]).countTestCases()
self.assertEqual(count, tests_count)
self.assertEqual(runner.test_loader.testNamePatterns, ['UnittestCase1'])
def test_loader_patterns_not_mutated_when_test_label_is_file_path(self):
runner = DiscoverRunner(test_name_patterns=['test_sample'], verbosity=0)
with change_cwd('.'), change_loader_patterns(['UnittestCase1']):
with self.assertRaises(RuntimeError):
runner.build_suite(['test_discover_runner.py'])
self.assertEqual(runner.test_loader.testNamePatterns, ['UnittestCase1'])
def test_file_path(self):
with change_cwd(".."):
count = DiscoverRunner(verbosity=0).build_suite(