diff options
author | Victor Stinner <vstinner@python.org> | 2023-09-28 17:04:01 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-28 17:04:01 (GMT) |
commit | 757cbd4f29c9e89b38b975e0463dc8ed331b2515 (patch) | |
tree | 84a65966c3e16e6833881568ad209ec936fac3ff /Lib/test/test_gdb/test_cfunction.py | |
parent | c4eda57345f579947b128e6148ab7f77de44bb88 (diff) | |
download | cpython-757cbd4f29c9e89b38b975e0463dc8ed331b2515.zip cpython-757cbd4f29c9e89b38b975e0463dc8ed331b2515.tar.gz cpython-757cbd4f29c9e89b38b975e0463dc8ed331b2515.tar.bz2 |
gh-109972: Enhance test_gdb (#110026)
* Split test_pycfunction.py: add test_cfunction_full.py.
Split the function into the following 6 functions. In verbose
mode, these "pycfunction" tests now log each tested call.
* test_pycfunction_noargs()
* test_pycfunction_o()
* test_pycfunction_varargs()
* test_pycfunction_varargs_keywords()
* test_pycfunction_fastcall()
* test_pycfunction_fastcall_keywords()
* Move get_gdb_repr() to PrettyPrintTests.
* Replace DebuggerTests.get_sample_script() with SAMPLE_SCRIPT.
* Rename checkout_hook_path to CHECKOUT_HOOK_PATH.
* Rename gdb_version to GDB_VERSION_TEXT.
* Replace (gdb_major_version, gdb_minor_version) with GDB_VERSION.
* run_gdb() uses "backslashreplace" error handler instead of "replace".
* Add check_gdb() function to util.py.
* Enhance support.check_cflags_pgo(): check also for sysconfig
PGO_PROF_USE_FLAG (if available) in compiler flags.
* Move some SkipTest checks to test_gdb/__init__.py.
* Elaborate why gdb cannot be tested on Windows: gdb doesn't support
PDB debug symbol files.
Diffstat (limited to 'Lib/test/test_gdb/test_cfunction.py')
-rw-r--r-- | Lib/test/test_gdb/test_cfunction.py | 114 |
1 files changed, 58 insertions, 56 deletions
diff --git a/Lib/test/test_gdb/test_cfunction.py b/Lib/test/test_gdb/test_cfunction.py index 55796d0..0a62014 100644 --- a/Lib/test/test_gdb/test_cfunction.py +++ b/Lib/test/test_gdb/test_cfunction.py @@ -1,8 +1,6 @@ -import re import textwrap import unittest from test import support -from test.support import python_is_optimized from .util import setup_module, DebuggerTests @@ -11,10 +9,22 @@ def setUpModule(): setup_module() -@unittest.skipIf(python_is_optimized(), +@unittest.skipIf(support.python_is_optimized(), "Python was compiled with optimizations") @support.requires_resource('cpu') class CFunctionTests(DebuggerTests): + def check(self, func_name, cmd): + # Verify with "py-bt": + gdb_output = self.get_stack_trace( + cmd, + breakpoint=func_name, + cmds_after_breakpoint=['bt', 'py-bt'], + # bpo-45207: Ignore 'Function "meth_varargs" not + # defined.' message in stderr. + ignore_stderr=True, + ) + self.assertIn(f'<built-in method {func_name}', gdb_output) + # Some older versions of gdb will fail with # "Cannot find new threads: generic error" # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround @@ -24,60 +34,52 @@ class CFunctionTests(DebuggerTests): # This is because we are calling functions from an "external" module # (_testcapimodule) rather than compiled-in functions. It seems difficult # to suppress these. See also the comment in DebuggerTests.get_stack_trace - def test_pycfunction(self): + def check_pycfunction(self, func_name, args): 'Verify that "py-bt" displays invocations of PyCFunction instances' - # bpo-46600: If the compiler inlines _null_to_none() in meth_varargs() - # (ex: clang -Og), _null_to_none() is the frame #1. Otherwise, - # meth_varargs() is the frame #1. - expected_frame = r'#(1|2)' + + if support.verbose: + print() + # Various optimizations multiply the code paths by which these are # called, so test a variety of calling conventions. - for func_name, args in ( - ('meth_varargs', ''), - ('meth_varargs_keywords', ''), - ('meth_o', '[]'), - ('meth_noargs', ''), - ('meth_fastcall', ''), - ('meth_fastcall_keywords', ''), + for obj in ( + '_testcapi', + '_testcapi.MethClass', + '_testcapi.MethClass()', + '_testcapi.MethStatic()', + + # XXX: bound methods don't yet give nice tracebacks + # '_testcapi.MethInstance()', ): - for obj in ( - '_testcapi', - '_testcapi.MethClass', - '_testcapi.MethClass()', - '_testcapi.MethStatic()', - - # XXX: bound methods don't yet give nice tracebacks - # '_testcapi.MethInstance()', - ): - with self.subTest(f'{obj}.{func_name}'): - cmd = textwrap.dedent(f''' - import _testcapi - def foo(): - {obj}.{func_name}({args}) - def bar(): - foo() - bar() - ''') - # Verify with "py-bt": - gdb_output = self.get_stack_trace( - cmd, - breakpoint=func_name, - cmds_after_breakpoint=['bt', 'py-bt'], - # bpo-45207: Ignore 'Function "meth_varargs" not - # defined.' message in stderr. - ignore_stderr=True, - ) - self.assertIn(f'<built-in method {func_name}', gdb_output) - - # Verify with "py-bt-full": - gdb_output = self.get_stack_trace( - cmd, - breakpoint=func_name, - cmds_after_breakpoint=['py-bt-full'], - # bpo-45207: Ignore 'Function "meth_varargs" not - # defined.' message in stderr. - ignore_stderr=True, - ) - regex = expected_frame - regex += re.escape(f' <built-in method {func_name}') - self.assertRegex(gdb_output, regex) + with self.subTest(f'{obj}.{func_name}'): + call = f'{obj}.{func_name}({args})' + cmd = textwrap.dedent(f''' + import _testcapi + def foo(): + {call} + def bar(): + foo() + bar() + ''') + if support.verbose: + print(f' test call: {call}', flush=True) + + self.check(func_name, cmd) + + def test_pycfunction_noargs(self): + self.check_pycfunction('meth_noargs', '') + + def test_pycfunction_o(self): + self.check_pycfunction('meth_o', '[]') + + def test_pycfunction_varargs(self): + self.check_pycfunction('meth_varargs', '') + + def test_pycfunction_varargs_keywords(self): + self.check_pycfunction('meth_varargs_keywords', '') + + def test_pycfunction_fastcall(self): + self.check_pycfunction('meth_fastcall', '') + + def test_pycfunction_fastcall_keywords(self): + self.check_pycfunction('meth_fastcall_keywords', '') |