Skip to content

Commit 9dd7e45

Browse files
vstinnersrinivasreddy
authored andcommitted
pythongh-93649: Move _testcapi tests to specific files (python#129544)
Move many functions from _testcapimodule.c into more specific files in Modules/_testcapi/. In moved code: * Replace get_testerror() with PyExc_AssertionError. * Replace raiseTestError() with PyErr_Format(PyExc_AssertionError, ...).
1 parent 8c655c7 commit 9dd7e45

File tree

9 files changed

+651
-646
lines changed

9 files changed

+651
-646
lines changed

Lib/test/test_capi/test_misc.py

-36
Original file line numberDiff line numberDiff line change
@@ -403,42 +403,6 @@ def test_buildvalue_ints(self):
403403
def test_buildvalue_N(self):
404404
_testcapi.test_buildvalue_N()
405405

406-
def check_negative_refcount(self, code):
407-
# bpo-35059: Check that Py_DECREF() reports the correct filename
408-
# when calling _Py_NegativeRefcount() to abort Python.
409-
code = textwrap.dedent(code)
410-
rc, out, err = assert_python_failure('-c', code)
411-
self.assertRegex(err,
412-
br'_testcapimodule\.c:[0-9]+: '
413-
br'_Py_NegativeRefcount: Assertion failed: '
414-
br'object has negative ref count')
415-
416-
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
417-
'need _testcapi.negative_refcount()')
418-
def test_negative_refcount(self):
419-
code = """
420-
import _testcapi
421-
from test import support
422-
423-
with support.SuppressCrashReport():
424-
_testcapi.negative_refcount()
425-
"""
426-
self.check_negative_refcount(code)
427-
428-
@unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'),
429-
'need _testcapi.decref_freed_object()')
430-
@support.skip_if_sanitizer("use after free on purpose",
431-
address=True, memory=True, ub=True)
432-
def test_decref_freed_object(self):
433-
code = """
434-
import _testcapi
435-
from test import support
436-
437-
with support.SuppressCrashReport():
438-
_testcapi.decref_freed_object()
439-
"""
440-
self.check_negative_refcount(code)
441-
442406
def test_trashcan_subclass(self):
443407
# bpo-35983: Check that the trashcan mechanism for "list" is NOT
444408
# activated when its tp_dealloc is being called by a subclass

Lib/test/test_capi/test_object.py

+40
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import enum
2+
import textwrap
23
import unittest
34
from test import support
45
from test.support import import_helper
56
from test.support import os_helper
67
from test.support import threading_helper
8+
from test.support.script_helper import assert_python_failure
9+
710

811
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
912
_testcapi = import_helper.import_module('_testcapi')
@@ -170,5 +173,42 @@ def silly_func(obj):
170173
self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list))
171174

172175

176+
class CAPITest(unittest.TestCase):
177+
def check_negative_refcount(self, code):
178+
# bpo-35059: Check that Py_DECREF() reports the correct filename
179+
# when calling _Py_NegativeRefcount() to abort Python.
180+
code = textwrap.dedent(code)
181+
rc, out, err = assert_python_failure('-c', code)
182+
self.assertRegex(err,
183+
br'object\.c:[0-9]+: '
184+
br'_Py_NegativeRefcount: Assertion failed: '
185+
br'object has negative ref count')
186+
187+
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
188+
'need _testcapi.negative_refcount()')
189+
def test_negative_refcount(self):
190+
code = """
191+
import _testcapi
192+
from test import support
193+
194+
with support.SuppressCrashReport():
195+
_testcapi.negative_refcount()
196+
"""
197+
self.check_negative_refcount(code)
198+
199+
@unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'),
200+
'need _testcapi.decref_freed_object()')
201+
@support.skip_if_sanitizer("use after free on purpose",
202+
address=True, memory=True, ub=True)
203+
def test_decref_freed_object(self):
204+
code = """
205+
import _testcapi
206+
from test import support
207+
208+
with support.SuppressCrashReport():
209+
_testcapi.decref_freed_object()
210+
"""
211+
self.check_negative_refcount(code)
212+
173213
if __name__ == "__main__":
174214
unittest.main()

Modules/_testcapi/dict.c

+78
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,83 @@ dict_popstring_null(PyObject *self, PyObject *args)
181181
RETURN_INT(PyDict_PopString(dict, key, NULL));
182182
}
183183

184+
185+
static int
186+
test_dict_inner(PyObject *self, int count)
187+
{
188+
Py_ssize_t pos = 0, iterations = 0;
189+
int i;
190+
PyObject *dict = PyDict_New();
191+
PyObject *v, *k;
192+
193+
if (dict == NULL)
194+
return -1;
195+
196+
for (i = 0; i < count; i++) {
197+
v = PyLong_FromLong(i);
198+
if (v == NULL) {
199+
goto error;
200+
}
201+
if (PyDict_SetItem(dict, v, v) < 0) {
202+
Py_DECREF(v);
203+
goto error;
204+
}
205+
Py_DECREF(v);
206+
}
207+
208+
k = v = UNINITIALIZED_PTR;
209+
while (PyDict_Next(dict, &pos, &k, &v)) {
210+
PyObject *o;
211+
iterations++;
212+
213+
assert(k != UNINITIALIZED_PTR);
214+
assert(v != UNINITIALIZED_PTR);
215+
i = PyLong_AS_LONG(v) + 1;
216+
o = PyLong_FromLong(i);
217+
if (o == NULL) {
218+
goto error;
219+
}
220+
if (PyDict_SetItem(dict, k, o) < 0) {
221+
Py_DECREF(o);
222+
goto error;
223+
}
224+
Py_DECREF(o);
225+
k = v = UNINITIALIZED_PTR;
226+
}
227+
assert(k == UNINITIALIZED_PTR);
228+
assert(v == UNINITIALIZED_PTR);
229+
230+
Py_DECREF(dict);
231+
232+
if (iterations != count) {
233+
PyErr_SetString(
234+
PyExc_AssertionError,
235+
"test_dict_iteration: dict iteration went wrong ");
236+
return -1;
237+
} else {
238+
return 0;
239+
}
240+
error:
241+
Py_DECREF(dict);
242+
return -1;
243+
}
244+
245+
246+
static PyObject*
247+
test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
248+
{
249+
int i;
250+
251+
for (i = 0; i < 200; i++) {
252+
if (test_dict_inner(self, i) < 0) {
253+
return NULL;
254+
}
255+
}
256+
257+
Py_RETURN_NONE;
258+
}
259+
260+
184261
static PyMethodDef test_methods[] = {
185262
{"dict_containsstring", dict_containsstring, METH_VARARGS},
186263
{"dict_getitemref", dict_getitemref, METH_VARARGS},
@@ -191,6 +268,7 @@ static PyMethodDef test_methods[] = {
191268
{"dict_pop_null", dict_pop_null, METH_VARARGS},
192269
{"dict_popstring", dict_popstring, METH_VARARGS},
193270
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
271+
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
194272
{NULL},
195273
};
196274

Modules/_testcapi/float.c

+59
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,68 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data,
9999
return PyFloat_FromDouble(d);
100100
}
101101

102+
103+
/* Test PyOS_string_to_double. */
104+
static PyObject *
105+
test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored))
106+
{
107+
double result;
108+
const char *msg;
109+
110+
#define CHECK_STRING(STR, expected) \
111+
do { \
112+
result = PyOS_string_to_double(STR, NULL, NULL); \
113+
if (result == -1.0 && PyErr_Occurred()) { \
114+
return NULL; \
115+
} \
116+
if (result != (double)expected) { \
117+
msg = "conversion of " STR " to float failed"; \
118+
goto fail; \
119+
} \
120+
} while (0)
121+
122+
#define CHECK_INVALID(STR) \
123+
do { \
124+
result = PyOS_string_to_double(STR, NULL, NULL); \
125+
if (result == -1.0 && PyErr_Occurred()) { \
126+
if (PyErr_ExceptionMatches(PyExc_ValueError)) { \
127+
PyErr_Clear(); \
128+
} \
129+
else { \
130+
return NULL; \
131+
} \
132+
} \
133+
else { \
134+
msg = "conversion of " STR " didn't raise ValueError"; \
135+
goto fail; \
136+
} \
137+
} while (0)
138+
139+
CHECK_STRING("0.1", 0.1);
140+
CHECK_STRING("1.234", 1.234);
141+
CHECK_STRING("-1.35", -1.35);
142+
CHECK_STRING(".1e01", 1.0);
143+
CHECK_STRING("2.e-2", 0.02);
144+
145+
CHECK_INVALID(" 0.1");
146+
CHECK_INVALID("\t\n-3");
147+
CHECK_INVALID(".123 ");
148+
CHECK_INVALID("3\n");
149+
CHECK_INVALID("123abc");
150+
151+
Py_RETURN_NONE;
152+
fail:
153+
PyErr_Format(PyExc_AssertionError, "test_string_to_double: %s", msg);
154+
return NULL;
155+
#undef CHECK_STRING
156+
#undef CHECK_INVALID
157+
}
158+
159+
102160
static PyMethodDef test_methods[] = {
103161
_TESTCAPI_FLOAT_PACK_METHODDEF
104162
_TESTCAPI_FLOAT_UNPACK_METHODDEF
163+
{"test_string_to_double", test_string_to_double, METH_NOARGS},
105164
{NULL},
106165
};
107166

Modules/_testcapi/list.c

+45-6
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,61 @@ list_extend(PyObject* Py_UNUSED(module), PyObject *args)
6060
}
6161

6262

63+
static PyObject*
64+
test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored))
65+
{
66+
PyObject* list;
67+
int i;
68+
69+
/* SF bug 132008: PyList_Reverse segfaults */
70+
#define NLIST 30
71+
list = PyList_New(NLIST);
72+
if (list == (PyObject*)NULL)
73+
return (PyObject*)NULL;
74+
/* list = range(NLIST) */
75+
for (i = 0; i < NLIST; ++i) {
76+
PyObject* anint = PyLong_FromLong(i);
77+
if (anint == (PyObject*)NULL) {
78+
Py_DECREF(list);
79+
return (PyObject*)NULL;
80+
}
81+
PyList_SET_ITEM(list, i, anint);
82+
}
83+
/* list.reverse(), via PyList_Reverse() */
84+
i = PyList_Reverse(list); /* should not blow up! */
85+
if (i != 0) {
86+
Py_DECREF(list);
87+
return (PyObject*)NULL;
88+
}
89+
/* Check that list == range(29, -1, -1) now */
90+
for (i = 0; i < NLIST; ++i) {
91+
PyObject* anint = PyList_GET_ITEM(list, i);
92+
if (PyLong_AS_LONG(anint) != NLIST-1-i) {
93+
PyErr_SetString(PyExc_AssertionError,
94+
"test_list_api: reverse screwed up");
95+
Py_DECREF(list);
96+
return (PyObject*)NULL;
97+
}
98+
}
99+
Py_DECREF(list);
100+
#undef NLIST
101+
102+
Py_RETURN_NONE;
103+
}
104+
105+
63106
static PyMethodDef test_methods[] = {
64107
{"list_get_size", list_get_size, METH_O},
65108
{"list_get_item", list_get_item, METH_VARARGS},
66109
{"list_set_item", list_set_item, METH_VARARGS},
67110
{"list_clear", list_clear, METH_O},
68111
{"list_extend", list_extend, METH_VARARGS},
69-
112+
{"test_list_api", test_list_api, METH_NOARGS},
70113
{NULL},
71114
};
72115

73116
int
74117
_PyTestCapi_Init_List(PyObject *m)
75118
{
76-
if (PyModule_AddFunctions(m, test_methods) < 0) {
77-
return -1;
78-
}
79-
80-
return 0;
119+
return PyModule_AddFunctions(m, test_methods);
81120
}

0 commit comments

Comments
 (0)