Skip to content

Commit 9880687

Browse files
committed
add test using _testcapimodule
1 parent 7415668 commit 9880687

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

Lib/test/test_capi/test_misc.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2884,5 +2884,26 @@ def test_pack_version_ctypes(self):
28842884
self.assertEqual(result, expected)
28852885

28862886

2887+
class TestCEval(unittest.TestCase):
2888+
def test_ceval_decref(self):
2889+
def f():
2890+
l = []
2891+
del l
2892+
2893+
def g():
2894+
l = [], []
2895+
del l
2896+
2897+
_testcapi.toggle_reftrace_counter()
2898+
f()
2899+
refs = _testcapi.toggle_reftrace_counter()
2900+
self.assertEqual(refs, (1, 1))
2901+
2902+
_testcapi.toggle_reftrace_counter()
2903+
g()
2904+
refs = _testcapi.toggle_reftrace_counter()
2905+
self.assertEqual(refs, (3, 3))
2906+
2907+
28872908
if __name__ == "__main__":
28882909
unittest.main()

Modules/_testcapimodule.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2514,6 +2514,47 @@ code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
25142514
return PyLong_FromInt32(PyCode_Addr2Line(code, offset));
25152515
}
25162516

2517+
typedef struct {
2518+
Py_ssize_t create_count;
2519+
Py_ssize_t destroy_count;
2520+
void *prev_data;
2521+
int (*prev_tracer)(PyObject *, PyRefTracerEvent, void *);
2522+
} reftrace_counter_data;
2523+
2524+
static int _reftrace_counter(PyObject *obj, PyRefTracerEvent event, void *counter_data)
2525+
{
2526+
if (event == PyRefTracer_CREATE) {
2527+
((reftrace_counter_data *)counter_data)->create_count++;
2528+
} else {
2529+
((reftrace_counter_data *)counter_data)->destroy_count++;
2530+
}
2531+
return 0;
2532+
}
2533+
2534+
// A very simple reftrace counter for very simple tests
2535+
static PyObject *
2536+
toggle_reftrace_counter(PyObject *ob, PyObject *Py_UNUSED(args))
2537+
{
2538+
static reftrace_counter_data counter_data = {0, 0, NULL, (void *)toggle_reftrace_counter}; // sentinel
2539+
2540+
if (counter_data.prev_tracer == (void *)toggle_reftrace_counter) {
2541+
// toggle counter on
2542+
counter_data.create_count = counter_data.destroy_count = 0;
2543+
counter_data.prev_tracer = PyRefTracer_GetTracer(&counter_data.prev_data);
2544+
2545+
PyRefTracer_SetTracer(_reftrace_counter, &counter_data);
2546+
2547+
Py_RETURN_NONE;
2548+
}
2549+
2550+
// toggle counter off
2551+
PyRefTracer_SetTracer(counter_data.prev_tracer, counter_data.prev_data);
2552+
2553+
counter_data.prev_tracer = (void *)toggle_reftrace_counter;
2554+
2555+
return Py_BuildValue("(nn)", counter_data.create_count, counter_data.destroy_count);
2556+
}
2557+
25172558

25182559
static PyMethodDef TestMethods[] = {
25192560
{"set_errno", set_errno, METH_VARARGS},
@@ -2608,6 +2649,7 @@ static PyMethodDef TestMethods[] = {
26082649
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
26092650
{"test_atexit", test_atexit, METH_NOARGS},
26102651
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
2652+
{"toggle_reftrace_counter", toggle_reftrace_counter, METH_NOARGS},
26112653
{NULL, NULL} /* sentinel */
26122654
};
26132655

0 commit comments

Comments
 (0)