]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-127637: add tests for `dis` command-line interface (#127759)
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Mon, 9 Dec 2024 18:02:22 +0000 (19:02 +0100)
committerGitHub <noreply@github.com>
Mon, 9 Dec 2024 18:02:22 +0000 (18:02 +0000)
Lib/dis.py
Lib/test/test_dis.py
Misc/NEWS.d/next/Tests/2024-12-09-12-35-44.gh-issue-127637.KLx-9I.rst [new file with mode: 0644]

index 6b3e9ef8399e1c51aca2b0f5e5ec9579714f1b13..aa22404c6687e165c363aacbdc254d69bab1bc6b 100644 (file)
@@ -1115,7 +1115,7 @@ class Bytecode:
             return output.getvalue()
 
 
-def main():
+def main(args=None):
     import argparse
 
     parser = argparse.ArgumentParser()
@@ -1128,7 +1128,7 @@ def main():
     parser.add_argument('-S', '--specialized', action='store_true',
                         help='show specialized bytecode')
     parser.add_argument('infile', nargs='?', default='-')
-    args = parser.parse_args()
+    args = parser.parse_args(args=args)
     if args.infile == '-':
         name = '<stdin>'
         source = sys.stdin.buffer.read()
index 55890e58ed4bae7735d006cf4558fad511f4cf12..c719f571152d61c967bdc06aa6c1d18cb3870cf0 100644 (file)
@@ -5,15 +5,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"]
 
@@ -2426,5 +2430,119 @@ 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'),
+            ('-P', '--show-positions'),
+            ('-S', '--specialized'),
+        ]
+
+        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
+                        LOAD_CONST               0 (None)
+                        RETURN_VALUE
+        '''
+        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       LOAD_CONST               0 (None)
+                       4       RETURN_VALUE
+        '''
+        for flag in ['-O', '--show-offsets']:
+            self.check_output(source, expect, flag)
+
+    def test_show_positions(self):
+        # test 'python -m dis -P/--show-positions'
+        source = 'pass'
+        expect = '''
+            0:0-1:0            RESUME                   0
+
+            1:0-1:4            LOAD_CONST               0 (None)
+            1:0-1:4            RETURN_VALUE
+        '''
+        for flag in ['-P', '--show-positions']:
+            self.check_output(source, expect, flag)
+
+    def test_specialized_code(self):
+        # test 'python -m dis -S/--specialized'
+        source = 'pass'
+        expect = '''
+            0           RESUME                   0
+
+            1           LOAD_CONST_IMMORTAL      0 (None)
+                        RETURN_VALUE
+        '''
+        for flag in ['-S', '--specialized']:
+            self.check_output(source, expect, flag)
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Tests/2024-12-09-12-35-44.gh-issue-127637.KLx-9I.rst b/Misc/NEWS.d/next/Tests/2024-12-09-12-35-44.gh-issue-127637.KLx-9I.rst
new file mode 100644 (file)
index 0000000..ac5d982
--- /dev/null
@@ -0,0 +1 @@
+Add tests for the :mod:`dis` command-line interface. Patch by Bénédikt Tran.