[3.13] gh-127637: add tests for dis command-line interface (#127759) (#127781)

This commit is contained in:
Bénédikt Tran 2024-12-10 13:32:32 +01:00 committed by GitHub
parent 00d60623e9
commit 8bf5b89212
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 95 additions and 4 deletions

View file

@ -4,15 +4,19 @@ import contextlib
import dis
import functools
import io
import itertools
import opcode
import re
import sys
import tempfile
import textwrap
import types
import unittest
from test.support import (captured_stdout, requires_debug_ranges,
requires_specialization, cpython_only)
requires_specialization, cpython_only,
os_helper)
from test.support.bytecode_helper import BytecodeTestCase
import opcode
CACHE = dis.opmap["CACHE"]
@ -2281,5 +2285,91 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False):
False, None, None, instr.positions)
class TestDisCLI(unittest.TestCase):
def setUp(self):
self.filename = tempfile.mktemp()
self.addCleanup(os_helper.unlink, self.filename)
@staticmethod
def text_normalize(string):
"""Dedent *string* and strip it from its surrounding whitespaces.
This method is used by the other utility functions so that any
string to write or to match against can be freely indented.
"""
return textwrap.dedent(string).strip()
def set_source(self, content):
with open(self.filename, 'w') as fp:
fp.write(self.text_normalize(content))
def invoke_dis(self, *flags):
output = io.StringIO()
with contextlib.redirect_stdout(output):
dis.main(args=[*flags, self.filename])
return self.text_normalize(output.getvalue())
def check_output(self, source, expect, *flags):
with self.subTest(source=source, flags=flags):
self.set_source(source)
res = self.invoke_dis(*flags)
expect = self.text_normalize(expect)
self.assertListEqual(res.splitlines(), expect.splitlines())
def test_invocation(self):
# test various combinations of parameters
base_flags = [
('-C', '--show-caches'),
('-O', '--show-offsets'),
]
self.set_source('''
def f():
print(x)
return None
''')
for r in range(1, len(base_flags) + 1):
for choices in itertools.combinations(base_flags, r=r):
for args in itertools.product(*choices):
with self.subTest(args=args[1:]):
_ = self.invoke_dis(*args)
with self.assertRaises(SystemExit):
# suppress argparse error message
with contextlib.redirect_stderr(io.StringIO()):
_ = self.invoke_dis('--unknown')
def test_show_cache(self):
# test 'python -m dis -C/--show-caches'
source = 'print()'
expect = '''
0 RESUME 0
1 LOAD_NAME 0 (print)
PUSH_NULL
CALL 0
CACHE 0 (counter: 0)
CACHE 0 (func_version: 0)
CACHE 0
POP_TOP
RETURN_CONST 0 (None)
'''
for flag in ['-C', '--show-caches']:
self.check_output(source, expect, flag)
def test_show_offsets(self):
# test 'python -m dis -O/--show-offsets'
source = 'pass'
expect = '''
0 0 RESUME 0
1 2 RETURN_CONST 0 (None)
'''
for flag in ['-O', '--show-offsets']:
self.check_output(source, expect, flag)
if __name__ == "__main__":
unittest.main()