17db96d56Sopenharmony_ciimport dis
27db96d56Sopenharmony_ciimport sys
37db96d56Sopenharmony_ciimport textwrap
47db96d56Sopenharmony_ciimport unittest
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_cifrom test.support import os_helper, verbose
77db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_cidef example():
107db96d56Sopenharmony_ci    x = []
117db96d56Sopenharmony_ci    for i in range(1):
127db96d56Sopenharmony_ci        x.append(i)
137db96d56Sopenharmony_ci    x = "this is"
147db96d56Sopenharmony_ci    y = "an example"
157db96d56Sopenharmony_ci    print(x, y)
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciPy_DEBUG = hasattr(sys, 'gettotalrefcount')
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci@unittest.skipUnless(Py_DEBUG, "lltrace requires Py_DEBUG")
207db96d56Sopenharmony_ciclass TestLLTrace(unittest.TestCase):
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci    def run_code(self, code):
237db96d56Sopenharmony_ci        code = textwrap.dedent(code).strip()
247db96d56Sopenharmony_ci        with open(os_helper.TESTFN, 'w', encoding='utf-8') as fd:
257db96d56Sopenharmony_ci            self.addCleanup(os_helper.unlink, os_helper.TESTFN)
267db96d56Sopenharmony_ci            fd.write(code)
277db96d56Sopenharmony_ci        status, stdout, stderr = assert_python_ok(os_helper.TESTFN)
287db96d56Sopenharmony_ci        self.assertEqual(stderr, b"")
297db96d56Sopenharmony_ci        self.assertEqual(status, 0)
307db96d56Sopenharmony_ci        result = stdout.decode('utf-8')
317db96d56Sopenharmony_ci        if verbose:
327db96d56Sopenharmony_ci            print("\n\n--- code ---")
337db96d56Sopenharmony_ci            print(code)
347db96d56Sopenharmony_ci            print("\n--- stdout ---")
357db96d56Sopenharmony_ci            print(result)
367db96d56Sopenharmony_ci            print()
377db96d56Sopenharmony_ci        return result
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci    def test_lltrace(self):
407db96d56Sopenharmony_ci        stdout = self.run_code("""
417db96d56Sopenharmony_ci            def dont_trace_1():
427db96d56Sopenharmony_ci                a = "a"
437db96d56Sopenharmony_ci                a = 10 * a
447db96d56Sopenharmony_ci            def trace_me():
457db96d56Sopenharmony_ci                for i in range(3):
467db96d56Sopenharmony_ci                    +i
477db96d56Sopenharmony_ci            def dont_trace_2():
487db96d56Sopenharmony_ci                x = 42
497db96d56Sopenharmony_ci                y = -x
507db96d56Sopenharmony_ci            dont_trace_1()
517db96d56Sopenharmony_ci            __lltrace__ = 1
527db96d56Sopenharmony_ci            trace_me()
537db96d56Sopenharmony_ci            del __lltrace__
547db96d56Sopenharmony_ci            dont_trace_2()
557db96d56Sopenharmony_ci        """)
567db96d56Sopenharmony_ci        self.assertIn("GET_ITER", stdout)
577db96d56Sopenharmony_ci        self.assertIn("FOR_ITER", stdout)
587db96d56Sopenharmony_ci        self.assertIn("UNARY_POSITIVE", stdout)
597db96d56Sopenharmony_ci        self.assertIn("POP_TOP", stdout)
607db96d56Sopenharmony_ci        self.assertNotIn("BINARY_OP", stdout)
617db96d56Sopenharmony_ci        self.assertNotIn("UNARY_NEGATIVE", stdout)
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci        self.assertIn("'trace_me' in module '__main__'", stdout)
647db96d56Sopenharmony_ci        self.assertNotIn("dont_trace_1", stdout)
657db96d56Sopenharmony_ci        self.assertNotIn("'dont_trace_2' in module", stdout)
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci    def test_lltrace_different_module(self):
687db96d56Sopenharmony_ci        stdout = self.run_code("""
697db96d56Sopenharmony_ci            from test import test_lltrace
707db96d56Sopenharmony_ci            test_lltrace.__lltrace__ = 1
717db96d56Sopenharmony_ci            test_lltrace.example()
727db96d56Sopenharmony_ci        """)
737db96d56Sopenharmony_ci        self.assertIn("'example' in module 'test.test_lltrace'", stdout)
747db96d56Sopenharmony_ci        self.assertIn('LOAD_CONST', stdout)
757db96d56Sopenharmony_ci        self.assertIn('FOR_ITER', stdout)
767db96d56Sopenharmony_ci        self.assertIn('this is an example', stdout)
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci        # check that offsets match the output of dis.dis()
797db96d56Sopenharmony_ci        instr_map = {i.offset: i for i in dis.get_instructions(example)}
807db96d56Sopenharmony_ci        for line in stdout.splitlines():
817db96d56Sopenharmony_ci            offset, colon, opname_oparg = line.partition(":")
827db96d56Sopenharmony_ci            if not colon:
837db96d56Sopenharmony_ci                continue
847db96d56Sopenharmony_ci            offset = int(offset)
857db96d56Sopenharmony_ci            opname_oparg = opname_oparg.split()
867db96d56Sopenharmony_ci            if len(opname_oparg) == 2:
877db96d56Sopenharmony_ci                opname, oparg = opname_oparg
887db96d56Sopenharmony_ci                oparg = int(oparg)
897db96d56Sopenharmony_ci            else:
907db96d56Sopenharmony_ci                (opname,) = opname_oparg
917db96d56Sopenharmony_ci                oparg = None
927db96d56Sopenharmony_ci            self.assertEqual(instr_map[offset].opname, opname)
937db96d56Sopenharmony_ci            self.assertEqual(instr_map[offset].arg, oparg)
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci    def test_lltrace_does_not_crash_on_subscript_operator(self):
967db96d56Sopenharmony_ci        # If this test fails, it will reproduce a crash reported as
977db96d56Sopenharmony_ci        # bpo-34113. The crash happened at the command line console of
987db96d56Sopenharmony_ci        # debug Python builds with __lltrace__ enabled (only possible in console),
997db96d56Sopenharmony_ci        # when the internal Python stack was negatively adjusted
1007db96d56Sopenharmony_ci        stdout = self.run_code("""
1017db96d56Sopenharmony_ci            import code
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci            console = code.InteractiveConsole()
1047db96d56Sopenharmony_ci            console.push('__lltrace__ = 1')
1057db96d56Sopenharmony_ci            console.push('a = [1, 2, 3]')
1067db96d56Sopenharmony_ci            console.push('a[0] = 1')
1077db96d56Sopenharmony_ci            print('unreachable if bug exists')
1087db96d56Sopenharmony_ci        """)
1097db96d56Sopenharmony_ci        self.assertIn("unreachable if bug exists", stdout)
1107db96d56Sopenharmony_ci
1117db96d56Sopenharmony_ciif __name__ == "__main__":
1127db96d56Sopenharmony_ci    unittest.main()
113