Skip to content

Commit 3600300

Browse files
vstinnerpablogsal
andauthored
bpo-34279, regrtest: Issue a warning if no tests have been executed (GH-10801)
Co-Authored-By: Pablo Galindo <[email protected]>
1 parent 2e869a8 commit 3600300

File tree

4 files changed

+130
-7
lines changed

4 files changed

+130
-7
lines changed

‎Lib/test/regrtest.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
RESOURCE_DENIED = -3
242242
INTERRUPTED = -4
243243
CHILD_ERROR = -5 # error in a child process
244+
TEST_DID_NOT_RUN = -6 # error in a child process
244245

245246
# Minimum duration of a test to display its duration or to mention that
246247
# the test is running in background
@@ -300,6 +301,7 @@ def format_duration(seconds):
300301
RESOURCE_DENIED: '%s skipped (resource denied)',
301302
INTERRUPTED: '%s interrupted',
302303
CHILD_ERROR: '%s crashed',
304+
TEST_DID_NOT_RUN: '%s run no tests',
303305
}
304306

305307

@@ -548,6 +550,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
548550
resource_denieds = []
549551
environment_changed = []
550552
rerun = []
553+
run_no_tests = []
551554
first_result = None
552555
interrupted = False
553556

@@ -644,6 +647,8 @@ def accumulate_result(test, result):
644647
elif ok == RESOURCE_DENIED:
645648
skipped.append(test)
646649
resource_denieds.append(test)
650+
elif ok == TEST_DID_NOT_RUN:
651+
run_no_tests.append(test)
647652
elif ok != INTERRUPTED:
648653
raise ValueError("invalid test result: %r" % ok)
649654

@@ -925,6 +930,8 @@ def get_tests_result():
925930
result.append("FAILURE")
926931
elif fail_env_changed and environment_changed:
927932
result.append("ENV CHANGED")
933+
elif not any((good, bad, skipped, interrupted, environment_changed)):
934+
result.append("NO TEST RUN")
928935

929936
if interrupted:
930937
result.append("INTERRUPTED")
@@ -994,10 +1001,15 @@ def display_result():
9941001
print "expected to get skipped on", plat + "."
9951002

9961003
if rerun:
997-
print
1004+
print("")
9981005
print("%s:" % count(len(rerun), "re-run test"))
9991006
printlist(rerun)
10001007

1008+
if run_no_tests:
1009+
print("")
1010+
print("%s run no tests:" % count(len(run_no_tests), "test"))
1011+
printlist(run_no_tests)
1012+
10011013

10021014
display_result()
10031015

@@ -1109,6 +1121,7 @@ def runtest(test, verbose, quiet,
11091121
ENV_CHANGED test failed because it changed the execution environment
11101122
FAILED test failed
11111123
PASSED test passed
1124+
EMPTY_TEST_SUITE test ran no subtests.
11121125
"""
11131126

11141127
support.verbose = verbose # Tell tests to be moderately quiet
@@ -1344,6 +1357,8 @@ def runtest_inner(test, verbose, quiet, huntrleaks=False, pgo=False, testdir=Non
13441357
print >>sys.stderr, "test", test, "failed --", msg
13451358
sys.stderr.flush()
13461359
return FAILED, test_time
1360+
except support.TestDidNotRun:
1361+
return TEST_DID_NOT_RUN, test_time
13471362
except:
13481363
type, value = sys.exc_info()[:2]
13491364
if not pgo:

‎Lib/test/support/__init__.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
except ImportError:
3030
thread = None
3131

32-
__all__ = ["Error", "TestFailed", "ResourceDenied", "import_module",
32+
__all__ = ["Error", "TestFailed", "TestDidNotRun", "ResourceDenied", "import_module",
3333
"verbose", "use_resources", "max_memuse", "record_original_stdout",
3434
"get_original_stdout", "unload", "unlink", "rmtree", "forget",
3535
"is_resource_enabled", "requires", "requires_mac_ver",
@@ -53,6 +53,9 @@ class Error(Exception):
5353
class TestFailed(Error):
5454
"""Test failed."""
5555

56+
class TestDidNotRun(Error):
57+
"""Test did not run any subtests."""
58+
5659
class ResourceDenied(unittest.SkipTest):
5760
"""Test skipped because it requested a disallowed resource.
5861
@@ -1536,6 +1539,8 @@ def _run_suite(suite):
15361539
runner = BasicTestRunner()
15371540

15381541
result = runner.run(suite)
1542+
if not result.testsRun:
1543+
raise TestDidNotRun
15391544
if not result.wasSuccessful():
15401545
if len(result.errors) == 1 and not result.failures:
15411546
err = result.errors[0][1]

‎Lib/test/test_regrtest.py‎

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,24 @@ def setUp(self):
5151
self.tmptestdir = tempfile.mkdtemp()
5252
self.addCleanup(support.rmtree, self.tmptestdir)
5353

54-
def create_test(self, name=None, code=''):
54+
def create_test(self, name=None, code=None):
5555
if not name:
5656
name = 'noop%s' % BaseTestCase.TEST_UNIQUE_ID
5757
BaseTestCase.TEST_UNIQUE_ID += 1
5858

59+
if code is None:
60+
code = textwrap.dedent("""
61+
import unittest
62+
from test import support
63+
64+
class Tests(unittest.TestCase):
65+
def test_empty_test(self):
66+
pass
67+
68+
def test_main():
69+
support.run_unittest(Tests)
70+
""")
71+
5972
# test_regrtest cannot be run twice in parallel because
6073
# of setUp() and create_test()
6174
name = self.TESTNAME_PREFIX + name
@@ -94,7 +107,7 @@ def parse_executed_tests(self, output):
94107

95108
def check_executed_tests(self, output, tests, skipped=(), failed=(),
96109
env_changed=(), omitted=(),
97-
rerun=(),
110+
rerun=(), no_test_ran=(),
98111
randomize=False, interrupted=False,
99112
fail_env_changed=False):
100113
if isinstance(tests, str):
@@ -109,6 +122,8 @@ def check_executed_tests(self, output, tests, skipped=(), failed=(),
109122
omitted = [omitted]
110123
if isinstance(rerun, str):
111124
rerun = [rerun]
125+
if isinstance(no_test_ran, str):
126+
no_test_ran = [no_test_ran]
112127

113128
executed = self.parse_executed_tests(output)
114129
if randomize:
@@ -152,7 +167,7 @@ def list_regex(line_format, tests):
152167
self.check_line(output, regex)
153168

154169
good = (len(tests) - len(skipped) - len(failed)
155-
- len(omitted) - len(env_changed))
170+
- len(omitted) - len(env_changed) - len(no_test_ran))
156171
if good:
157172
regex = r'%s test%s OK\.$' % (good, plural(good))
158173
if not skipped and not failed and good > 1:
@@ -169,12 +184,16 @@ def list_regex(line_format, tests):
169184
result.append('ENV CHANGED')
170185
if interrupted:
171186
result.append('INTERRUPTED')
172-
if not result:
187+
if not any((good, result, failed, interrupted, skipped,
188+
env_changed, fail_env_changed)):
189+
result.append("NO TEST RUN")
190+
elif not result:
173191
result.append('SUCCESS')
174192
result = ', '.join(result)
175193
if rerun:
176194
self.check_line(output, 'Tests result: %s' % result)
177195
result = 'FAILURE then %s' % result
196+
178197
self.check_line(output, 'Tests result: %s' % result)
179198

180199
def parse_random_seed(self, output):
@@ -358,7 +377,17 @@ def test_resources(self):
358377
# test -u command line option
359378
tests = {}
360379
for resource in ('audio', 'network'):
361-
code = 'from test import support\nsupport.requires(%r)' % resource
380+
code = textwrap.dedent("""
381+
from test import support; support.requires(%r)
382+
import unittest
383+
class PassingTest(unittest.TestCase):
384+
def test_pass(self):
385+
pass
386+
387+
def test_main():
388+
support.run_unittest(PassingTest)
389+
""" % resource)
390+
362391
tests[resource] = self.create_test(resource, code)
363392
test_names = sorted(tests.values())
364393

@@ -669,6 +698,7 @@ def test_main():
669698
def test_rerun_fail(self):
670699
code = textwrap.dedent("""
671700
import unittest
701+
from test import support
672702
673703
class Tests(unittest.TestCase):
674704
def test_bug(self):
@@ -684,6 +714,76 @@ def test_main():
684714
self.check_executed_tests(output, [testname],
685715
failed=testname, rerun=testname)
686716

717+
def test_no_tests_ran(self):
718+
code = textwrap.dedent("""
719+
import unittest
720+
from test import support
721+
722+
class Tests(unittest.TestCase):
723+
def test_bug(self):
724+
pass
725+
726+
def test_main():
727+
support.run_unittest(Tests)
728+
""")
729+
testname = self.create_test(code=code)
730+
731+
output = self.run_tests("-m", "nosuchtest", testname, exitcode=0)
732+
self.check_executed_tests(output, [testname], no_test_ran=testname)
733+
734+
def test_no_tests_ran_multiple_tests_nonexistent(self):
735+
code = textwrap.dedent("""
736+
import unittest
737+
from test import support
738+
739+
class Tests(unittest.TestCase):
740+
def test_bug(self):
741+
pass
742+
743+
def test_main():
744+
support.run_unittest(Tests)
745+
""")
746+
testname = self.create_test(code=code)
747+
testname2 = self.create_test(code=code)
748+
749+
output = self.run_tests("-m", "nosuchtest",
750+
testname, testname2,
751+
exitcode=0)
752+
self.check_executed_tests(output, [testname, testname2],
753+
no_test_ran=[testname, testname2])
754+
755+
def test_no_test_ran_some_test_exist_some_not(self):
756+
code = textwrap.dedent("""
757+
import unittest
758+
from test import support
759+
760+
class Tests(unittest.TestCase):
761+
def test_bug(self):
762+
pass
763+
764+
def test_main():
765+
support.run_unittest(Tests)
766+
""")
767+
testname = self.create_test(code=code)
768+
other_code = textwrap.dedent("""
769+
import unittest
770+
from test import support
771+
772+
class Tests(unittest.TestCase):
773+
def test_other_bug(self):
774+
pass
775+
776+
def test_main():
777+
support.run_unittest(Tests)
778+
""")
779+
testname2 = self.create_test(code=other_code)
780+
781+
output = self.run_tests("-m", "nosuchtest", "-m", "test_other_bug",
782+
testname, testname2,
783+
exitcode=0)
784+
self.check_executed_tests(output, [testname, testname2],
785+
no_test_ran=[testname])
786+
687787

688788
class TestUtils(unittest.TestCase):
689789
def test_format_duration(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
regrtest issue a warning when no tests have been executed in a particular
2+
test file. Also, a new final result state is issued if no test have been
3+
executed across all test files. Patch by Pablo Galindo.

0 commit comments

Comments
 (0)