|
| 1 | +import math |
1 | 2 | import unittest |
2 | 3 | import sys |
3 | 4 | import _ast |
@@ -519,8 +520,46 @@ def test_compile_ast(self): |
519 | 520 | self.assertRaises(TypeError, compile, ast, '<ast>', 'exec') |
520 | 521 |
|
521 | 522 |
|
| 523 | +class TestStackSize(unittest.TestCase): |
| 524 | + # These tests check that the computed stack size for a code object |
| 525 | + # stays within reasonable bounds (see issue #21523 for an example |
| 526 | + # dysfunction). |
| 527 | + N = 100 |
| 528 | + |
| 529 | + def check_stack_size(self, code): |
| 530 | + # To assert that the alleged stack size is not O(N), we |
| 531 | + # check that it is smaller than log(N). |
| 532 | + if isinstance(code, str): |
| 533 | + code = compile(code, "<foo>", "single") |
| 534 | + max_size = math.ceil(math.log(len(code.co_code))) |
| 535 | + self.assertLessEqual(code.co_stacksize, max_size) |
| 536 | + |
| 537 | + def test_and(self): |
| 538 | + self.check_stack_size("x and " * self.N + "x") |
| 539 | + |
| 540 | + def test_or(self): |
| 541 | + self.check_stack_size("x or " * self.N + "x") |
| 542 | + |
| 543 | + def test_and_or(self): |
| 544 | + self.check_stack_size("x and x or " * self.N + "x") |
| 545 | + |
| 546 | + def test_chained_comparison(self): |
| 547 | + self.check_stack_size("x < " * self.N + "x") |
| 548 | + |
| 549 | + def test_if_else(self): |
| 550 | + self.check_stack_size("x if x else " * self.N + "x") |
| 551 | + |
| 552 | + def test_binop(self): |
| 553 | + self.check_stack_size("x + " * self.N + "x") |
| 554 | + |
| 555 | + def test_func_and(self): |
| 556 | + code = "def f(x):\n" |
| 557 | + code += " x and x\n" * self.N |
| 558 | + self.check_stack_size(code) |
| 559 | + |
| 560 | + |
522 | 561 | def test_main(): |
523 | | - test_support.run_unittest(TestSpecifics) |
| 562 | + test_support.run_unittest(__name__) |
524 | 563 |
|
525 | 564 | if __name__ == "__main__": |
526 | | - test_main() |
| 565 | + unittest.main() |
0 commit comments