cpython/Modules/_testcapimodule.c
Thomas Heller 3457e4bd80 New support functions for test_getargs2.
Theres now a separate function for each of the format codes
b, B, H, I, k, i, l, L, K.
2003-04-24 16:14:27 +00:00

643 lines
16 KiB
C

/*
* C Extension module to test Python interpreter C APIs.
*
* The 'test_*' functions exported by this module are run as part of the
* standard Python regression test, via Lib/test/test_capi.py.
*/
#include "Python.h"
#ifdef WITH_THREAD
#include "pythread.h"
#endif /* WITH_THREAD */
static PyObject *TestError; /* set to exception object in init */
/* Raise TestError with test_name + ": " + msg, and return NULL. */
static PyObject *
raiseTestError(const char* test_name, const char* msg)
{
char buf[2048];
if (strlen(test_name) + strlen(msg) > sizeof(buf) - 50)
PyErr_SetString(TestError, "internal error msg too large");
else {
PyOS_snprintf(buf, sizeof(buf), "%s: %s", test_name, msg);
PyErr_SetString(TestError, buf);
}
return NULL;
}
/* Test #defines from pyconfig.h (particularly the SIZEOF_* defines).
The ones derived from autoconf on the UNIX-like OSes can be relied
upon (in the absence of sloppy cross-compiling), but the Windows
platforms have these hardcoded. Better safe than sorry.
*/
static PyObject*
sizeof_error(const char* fatname, const char* typename,
int expected, int got)
{
char buf[1024];
PyOS_snprintf(buf, sizeof(buf),
"%.200s #define == %d but sizeof(%.200s) == %d",
fatname, expected, typename, got);
PyErr_SetString(TestError, buf);
return (PyObject*)NULL;
}
static PyObject*
test_config(PyObject *self)
{
#define CHECK_SIZEOF(FATNAME, TYPE) \
if (FATNAME != sizeof(TYPE)) \
return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE))
CHECK_SIZEOF(SIZEOF_SHORT, short);
CHECK_SIZEOF(SIZEOF_INT, int);
CHECK_SIZEOF(SIZEOF_LONG, long);
CHECK_SIZEOF(SIZEOF_VOID_P, void*);
CHECK_SIZEOF(SIZEOF_TIME_T, time_t);
#ifdef HAVE_LONG_LONG
CHECK_SIZEOF(SIZEOF_LONG_LONG, PY_LONG_LONG);
#endif
#undef CHECK_SIZEOF
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
test_list_api(PyObject *self)
{
PyObject* list;
int i;
/* SF bug 132008: PyList_Reverse segfaults */
#define NLIST 30
list = PyList_New(NLIST);
if (list == (PyObject*)NULL)
return (PyObject*)NULL;
/* list = range(NLIST) */
for (i = 0; i < NLIST; ++i) {
PyObject* anint = PyInt_FromLong(i);
if (anint == (PyObject*)NULL) {
Py_DECREF(list);
return (PyObject*)NULL;
}
PyList_SET_ITEM(list, i, anint);
}
/* list.reverse(), via PyList_Reverse() */
i = PyList_Reverse(list); /* should not blow up! */
if (i != 0) {
Py_DECREF(list);
return (PyObject*)NULL;
}
/* Check that list == range(29, -1, -1) now */
for (i = 0; i < NLIST; ++i) {
PyObject* anint = PyList_GET_ITEM(list, i);
if (PyInt_AS_LONG(anint) != NLIST-1-i) {
PyErr_SetString(TestError,
"test_list_api: reverse screwed up");
Py_DECREF(list);
return (PyObject*)NULL;
}
}
Py_DECREF(list);
#undef NLIST
Py_INCREF(Py_None);
return Py_None;
}
static int
test_dict_inner(int count)
{
int pos = 0, iterations = 0, i;
PyObject *dict = PyDict_New();
PyObject *v, *k;
if (dict == NULL)
return -1;
for (i = 0; i < count; i++) {
v = PyInt_FromLong(i);
PyDict_SetItem(dict, v, v);
Py_DECREF(v);
}
while (PyDict_Next(dict, &pos, &k, &v)) {
PyObject *o;
iterations++;
i = PyInt_AS_LONG(v) + 1;
o = PyInt_FromLong(i);
if (o == NULL)
return -1;
if (PyDict_SetItem(dict, k, o) < 0) {
Py_DECREF(o);
return -1;
}
Py_DECREF(o);
}
Py_DECREF(dict);
if (iterations != count) {
PyErr_SetString(
TestError,
"test_dict_iteration: dict iteration went wrong ");
return -1;
} else {
return 0;
}
}
static PyObject*
test_dict_iteration(PyObject* self)
{
int i;
for (i = 0; i < 200; i++) {
if (test_dict_inner(i) < 0) {
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
/* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG)
PyLong_{As, From}{Unsigned,}LongLong().
Note that the meat of the test is contained in testcapi_long.h.
This is revolting, but delicate code duplication is worse: "almost
exactly the same" code is needed to test PY_LONG_LONG, but the ubiquitous
dependence on type names makes it impossible to use a parameterized
function. A giant macro would be even worse than this. A C++ template
would be perfect.
The "report an error" functions are deliberately not part of the #include
file: if the test fails, you can set a breakpoint in the appropriate
error function directly, and crawl back from there in the debugger.
*/
#define UNBIND(X) Py_DECREF(X); (X) = NULL
static PyObject *
raise_test_long_error(const char* msg)
{
return raiseTestError("test_long_api", msg);
}
#define TESTNAME test_long_api_inner
#define TYPENAME long
#define F_S_TO_PY PyLong_FromLong
#define F_PY_TO_S PyLong_AsLong
#define F_U_TO_PY PyLong_FromUnsignedLong
#define F_PY_TO_U PyLong_AsUnsignedLong
#include "testcapi_long.h"
static PyObject *
test_long_api(PyObject* self)
{
return TESTNAME(raise_test_long_error);
}
#undef TESTNAME
#undef TYPENAME
#undef F_S_TO_PY
#undef F_PY_TO_S
#undef F_U_TO_PY
#undef F_PY_TO_U
#ifdef HAVE_LONG_LONG
static PyObject *
raise_test_longlong_error(const char* msg)
{
return raiseTestError("test_longlong_api", msg);
}
#define TESTNAME test_longlong_api_inner
#define TYPENAME PY_LONG_LONG
#define F_S_TO_PY PyLong_FromLongLong
#define F_PY_TO_S PyLong_AsLongLong
#define F_U_TO_PY PyLong_FromUnsignedLongLong
#define F_PY_TO_U PyLong_AsUnsignedLongLong
#include "testcapi_long.h"
static PyObject *
test_longlong_api(PyObject* self)
{
return TESTNAME(raise_test_longlong_error);
}
#undef TESTNAME
#undef TYPENAME
#undef F_S_TO_PY
#undef F_PY_TO_S
#undef F_U_TO_PY
#undef F_PY_TO_U
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG
for both long and int arguments. The test may leak a little memory if
it fails.
*/
static PyObject *
test_L_code(PyObject *self)
{
PyObject *tuple, *num;
PY_LONG_LONG value;
tuple = PyTuple_New(1);
if (tuple == NULL)
return NULL;
num = PyLong_FromLong(42);
if (num == NULL)
return NULL;
PyTuple_SET_ITEM(tuple, 0, num);
value = -1;
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0)
return NULL;
if (value != 42)
return raiseTestError("test_L_code",
"L code returned wrong value for long 42");
Py_DECREF(num);
num = PyInt_FromLong(42);
if (num == NULL)
return NULL;
PyTuple_SET_ITEM(tuple, 0, num);
value = -1;
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0)
return NULL;
if (value != 42)
return raiseTestError("test_L_code",
"L code returned wrong value for int 42");
Py_DECREF(tuple);
Py_INCREF(Py_None);
return Py_None;
}
#endif /* ifdef HAVE_LONG_LONG */
/* Functions to call PyArg_ParseTuple with integer format codes,
and return the result.
*/
static PyObject *
getargs_b(PyObject *self, PyObject *args)
{
unsigned char value;
if (!PyArg_ParseTuple(args, "b", &value))
return NULL;
return PyLong_FromUnsignedLong((unsigned long)value);
}
static PyObject *
getargs_B(PyObject *self, PyObject *args)
{
unsigned char value;
if (!PyArg_ParseTuple(args, "B", &value))
return NULL;
return PyLong_FromUnsignedLong((unsigned long)value);
}
static PyObject *
getargs_H(PyObject *self, PyObject *args)
{
unsigned short value;
if (!PyArg_ParseTuple(args, "H", &value))
return NULL;
return PyLong_FromUnsignedLong((unsigned long)value);
}
static PyObject *
getargs_I(PyObject *self, PyObject *args)
{
unsigned int value;
if (!PyArg_ParseTuple(args, "I", &value))
return NULL;
return PyLong_FromUnsignedLong((unsigned long)value);
}
static PyObject *
getargs_k(PyObject *self, PyObject *args)
{
unsigned long value;
if (!PyArg_ParseTuple(args, "k", &value))
return NULL;
return PyLong_FromUnsignedLong(value);
}
static PyObject *
getargs_i(PyObject *self, PyObject *args)
{
int value;
if (!PyArg_ParseTuple(args, "i", &value))
return NULL;
return PyLong_FromLong((long)value);
}
static PyObject *
getargs_l(PyObject *self, PyObject *args)
{
long value;
if (!PyArg_ParseTuple(args, "l", &value))
return NULL;
return PyLong_FromLong(value);
}
#ifdef HAVE_LONG_LONG
static PyObject *
getargs_L(PyObject *self, PyObject *args)
{
PY_LONG_LONG value;
if (!PyArg_ParseTuple(args, "L", &value))
return NULL;
return PyLong_FromLongLong(value);
}
static PyObject *
getargs_K(PyObject *self, PyObject *args)
{
unsigned PY_LONG_LONG value;
if (!PyArg_ParseTuple(args, "K", &value))
return NULL;
return PyLong_FromUnsignedLongLong(value);
}
#endif
/* This function not only tests the 'k' getargs code, but also the
PyInt_AsUnsignedLongMask() and PyInt_AsUnsignedLongMask() functions. */
static PyObject *
test_k_code(PyObject *self)
{
PyObject *tuple, *num;
unsigned long value;
tuple = PyTuple_New(1);
if (tuple == NULL)
return NULL;
/* a number larger than ULONG_MAX even on 64-bit platforms */
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
if (num == NULL)
return NULL;
value = PyInt_AsUnsignedLongMask(num);
if (value != ULONG_MAX)
return raiseTestError("test_k_code",
"PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF");
PyTuple_SET_ITEM(tuple, 0, num);
value = -1;
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0)
return NULL;
if (value != ULONG_MAX)
return raiseTestError("test_k_code",
"k code returned wrong value for long 0xFFF...FFF");
Py_DECREF(num);
num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16);
if (num == NULL)
return NULL;
value = PyInt_AsUnsignedLongMask(num);
if (value != (unsigned long)-0x42)
return raiseTestError("test_k_code",
"PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF");
PyTuple_SET_ITEM(tuple, 0, num);
value = -1;
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0)
return NULL;
if (value != (unsigned long)-0x42)
return raiseTestError("test_k_code",
"k code returned wrong value for long -0xFFF..000042");
Py_DECREF(tuple);
Py_INCREF(Py_None);
return Py_None;
}
#ifdef Py_USING_UNICODE
/* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case
of an error.
*/
static PyObject *
test_u_code(PyObject *self)
{
PyObject *tuple, *obj;
Py_UNICODE *value;
int len;
tuple = PyTuple_New(1);
if (tuple == NULL)
return NULL;
obj = PyUnicode_Decode("test", strlen("test"),
"ascii", NULL);
if (obj == NULL)
return NULL;
PyTuple_SET_ITEM(tuple, 0, obj);
value = 0;
if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0)
return NULL;
if (value != PyUnicode_AS_UNICODE(obj))
return raiseTestError("test_u_code",
"u code returned wrong value for u'test'");
value = 0;
if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0)
return NULL;
if (value != PyUnicode_AS_UNICODE(obj) ||
len != PyUnicode_GET_SIZE(obj))
return raiseTestError("test_u_code",
"u# code returned wrong values for u'test'");
Py_DECREF(tuple);
Py_INCREF(Py_None);
return Py_None;
}
#endif
/* Simple test of _PyLong_NumBits and _PyLong_Sign. */
static PyObject *
test_long_numbits(PyObject *self)
{
struct triple {
long input;
size_t nbits;
int sign;
} testcases[] = {{0, 0, 0},
{1L, 1, 1},
{-1L, 1, -1},
{2L, 2, 1},
{-2L, 2, -1},
{3L, 2, 1},
{-3L, 2, -1},
{4L, 3, 1},
{-4L, 3, -1},
{0x7fffL, 15, 1}, /* one Python long digit */
{-0x7fffL, 15, -1},
{0xffffL, 16, 1},
{-0xffffL, 16, -1},
{0xfffffffL, 28, 1},
{-0xfffffffL, 28, -1}};
int i;
for (i = 0; i < sizeof(testcases) / sizeof(struct triple); ++i) {
PyObject *plong = PyLong_FromLong(testcases[i].input);
size_t nbits = _PyLong_NumBits(plong);
int sign = _PyLong_Sign(plong);
Py_DECREF(plong);
if (nbits != testcases[i].nbits)
return raiseTestError("test_long_numbits",
"wrong result for _PyLong_NumBits");
if (sign != testcases[i].sign)
return raiseTestError("test_long_numbits",
"wrong result for _PyLong_Sign");
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
raise_exception(PyObject *self, PyObject *args)
{
PyObject *exc;
PyObject *exc_args, *v;
int num_args, i;
if (!PyArg_ParseTuple(args, "Oi:raise_exception",
&exc, &num_args))
return NULL;
exc_args = PyTuple_New(num_args);
if (exc_args == NULL)
return NULL;
for (i = 0; i < num_args; ++i) {
v = PyInt_FromLong(i);
if (v == NULL) {
Py_DECREF(exc_args);
return NULL;
}
PyTuple_SET_ITEM(exc_args, i, v);
}
PyErr_SetObject(exc, exc_args);
return NULL;
}
#ifdef WITH_THREAD
void _make_call(void *callable)
{
PyObject *rc;
PyGILState_STATE s = PyGILState_Ensure();
rc = PyObject_CallFunction(callable, "");
Py_XDECREF(rc);
PyGILState_Release(s);
}
static PyObject *
test_thread_state(PyObject *self, PyObject *args)
{
PyObject *fn;
if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn))
return NULL;
/* Ensure Python is setup for threading */
PyEval_InitThreads();
/* Start a new thread for our callback. */
PyThread_start_new_thread( _make_call, fn);
/* Make the callback with the thread lock held by this thread */
_make_call(fn);
/* Do it all again, but this time with the thread-lock released */
Py_BEGIN_ALLOW_THREADS
_make_call(fn);
Py_END_ALLOW_THREADS
/* And once more with and without a thread
XXX - should use a lock and work out exactly what we are trying
to test <wink>
*/
Py_BEGIN_ALLOW_THREADS
PyThread_start_new_thread( _make_call, fn);
_make_call(fn);
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return Py_None;
}
#endif
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"test_config", (PyCFunction)test_config, METH_NOARGS},
{"test_list_api", (PyCFunction)test_list_api, METH_NOARGS},
{"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS},
{"test_long_api", (PyCFunction)test_long_api, METH_NOARGS},
{"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS},
{"test_k_code", (PyCFunction)test_k_code, METH_NOARGS},
{"getargs_b", (PyCFunction)getargs_b, METH_VARARGS},
{"getargs_B", (PyCFunction)getargs_B, METH_VARARGS},
{"getargs_H", (PyCFunction)getargs_H, METH_VARARGS},
{"getargs_I", (PyCFunction)getargs_I, METH_VARARGS},
{"getargs_k", (PyCFunction)getargs_k, METH_VARARGS},
{"getargs_i", (PyCFunction)getargs_i, METH_VARARGS},
{"getargs_l", (PyCFunction)getargs_l, METH_VARARGS},
#ifdef HAVE_LONG_LONG
{"getargs_L", (PyCFunction)getargs_L, METH_VARARGS},
{"getargs_K", (PyCFunction)getargs_K, METH_VARARGS},
{"test_longlong_api", (PyCFunction)test_longlong_api, METH_NOARGS},
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS},
#endif
#ifdef Py_USING_UNICODE
{"test_u_code", (PyCFunction)test_u_code, METH_NOARGS},
#endif
#ifdef WITH_THREAD
{"_test_thread_state", (PyCFunction)test_thread_state, METH_VARARGS},
#endif
{NULL, NULL} /* sentinel */
};
#define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);}
PyMODINIT_FUNC
init_testcapi(void)
{
PyObject *m;
m = Py_InitModule("_testcapi", TestMethods);
PyModule_AddObject(m, "UCHAR_MAX", PyInt_FromLong(UCHAR_MAX));
PyModule_AddObject(m, "USHRT_MAX", PyInt_FromLong(USHRT_MAX));
PyModule_AddObject(m, "UINT_MAX", PyLong_FromUnsignedLong(UINT_MAX));
PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX));
PyModule_AddObject(m, "INT_MIN", PyInt_FromLong(INT_MIN));
PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN));
PyModule_AddObject(m, "INT_MAX", PyInt_FromLong(INT_MAX));
PyModule_AddObject(m, "LONG_MAX", PyInt_FromLong(LONG_MAX));
TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
Py_INCREF(TestError);
PyModule_AddObject(m, "error", TestError);
}