[3.11] gh-108851: Fix tomllib recursion tests (#108853) (#109013)

gh-108851: Fix tomllib recursion tests (#108853)

* Add get_recursion_available() and get_recursion_depth() functions
  to the test.support module.
* Change infinite_recursion() default max_depth from 75 to 100.
* Fix test_tomllib recursion tests for WASI buildbots: reduce the
  recursion limit and compute the maximum nested array/dict depending
  on the current available recursion limit.
* test.pythoninfo logs sys.getrecursionlimit().
* Enhance test_sys tests on sys.getrecursionlimit()
  and sys.setrecursionlimit().

Backport notes:

* Set support.infinite_recursion() minimum to 4 frames.
* test_support.test_get_recursion_depth() uses limit-2, apparently
  f-string counts for 2 frames in Python 3.11.
* test_sys.test_setrecursionlimit_to_depth() tests depth+2 instead of
  depth+1.

(cherry picked from commit 8ff1142578)
This commit is contained in:
Victor Stinner 2023-09-06 18:40:39 +02:00 committed by GitHub
parent d61b8f9b8b
commit 95eb9849dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 41 deletions

View file

@ -698,6 +698,85 @@ class TestSupport(unittest.TestCase):
else:
self.assertTrue(support.has_strftime_extensions)
def test_get_recursion_depth(self):
# test support.get_recursion_depth()
code = textwrap.dedent("""
from test import support
import sys
def check(cond):
if not cond:
raise AssertionError("test failed")
# depth 1
check(support.get_recursion_depth() == 1)
# depth 2
def test_func():
check(support.get_recursion_depth() == 2)
test_func()
def test_recursive(depth, limit):
if depth >= limit:
# cannot call get_recursion_depth() at this depth,
# it can raise RecursionError
return
get_depth = support.get_recursion_depth()
print(f"test_recursive: {depth}/{limit}: "
f"get_recursion_depth() says {get_depth}")
check(get_depth == depth)
test_recursive(depth + 1, limit)
# depth up to 25
with support.infinite_recursion(max_depth=25):
limit = sys.getrecursionlimit()
print(f"test with sys.getrecursionlimit()={limit}")
# Use limit-2 since f-string seems to consume 2 frames.
test_recursive(2, limit - 2)
# depth up to 500
with support.infinite_recursion(max_depth=500):
limit = sys.getrecursionlimit()
print(f"test with sys.getrecursionlimit()={limit}")
# limit-2 since f-string seems to consume 2 frames
test_recursive(2, limit - 2)
""")
script_helper.assert_python_ok("-c", code)
def test_recursion(self):
# Test infinite_recursion() and get_recursion_available() functions.
def recursive_function(depth):
if depth:
recursive_function(depth - 1)
for max_depth in (5, 25, 250):
with support.infinite_recursion(max_depth):
available = support.get_recursion_available()
# Recursion up to 'available' additional frames should be OK.
recursive_function(available)
# Recursion up to 'available+1' additional frames must raise
# RecursionError. Avoid self.assertRaises(RecursionError) which
# can consume more than 3 frames and so raises RecursionError.
try:
recursive_function(available + 1)
except RecursionError:
pass
else:
self.fail("RecursionError was not raised")
# Test the bare minimumum: max_depth=4
with support.infinite_recursion(4):
try:
recursive_function(4)
except RecursionError:
pass
else:
self.fail("RecursionError was not raised")
#self.assertEqual(available, 2)
# XXX -follows a list of untested API
# make_legacy_pyc
# is_resource_enabled