summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_gdb/test_cfunction.py
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-09-28 17:04:01 (GMT)
committerGitHub <noreply@github.com>2023-09-28 17:04:01 (GMT)
commit757cbd4f29c9e89b38b975e0463dc8ed331b2515 (patch)
tree84a65966c3e16e6833881568ad209ec936fac3ff /Lib/test/test_gdb/test_cfunction.py
parentc4eda57345f579947b128e6148ab7f77de44bb88 (diff)
downloadcpython-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.py114
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', '')