diff options
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r-- | Modules/_testcapimodule.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6bc6da2..023e62e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1428,6 +1428,157 @@ test_string_from_format(PyObject *self, PyObject *args) #undef CHECK_1_FORMAT } +/* Coverage testing of capsule objects. */ + +static const char *capsule_name = "capsule name"; +static char *capsule_pointer = "capsule pointer"; +static char *capsule_context = "capsule context"; +static const char *capsule_error = NULL; +static int +capsule_destructor_call_count = 0; + +static void +capsule_destructor(PyObject *o) { + capsule_destructor_call_count++; + if (PyCapsule_GetContext(o) != capsule_context) { + capsule_error = "context did not match in destructor!"; + } else if (PyCapsule_GetDestructor(o) != capsule_destructor) { + capsule_error = "destructor did not match in destructor! (woah!)"; + } else if (PyCapsule_GetName(o) != capsule_name) { + capsule_error = "name did not match in destructor!"; + } else if (PyCapsule_GetPointer(o, capsule_name) != capsule_pointer) { + capsule_error = "pointer did not match in destructor!"; + } +} + +typedef struct { + char *name; + char *module; + char *attribute; +} known_capsule; + +static PyObject * +test_capsule(PyObject *self, PyObject *args) +{ + PyObject *object; + const char *error = NULL; + void *pointer; + void *pointer2; + known_capsule known_capsules[] = { + #define KNOWN_CAPSULE(module, name) { module "." name, module, name } + KNOWN_CAPSULE("_socket", "CAPI"), + KNOWN_CAPSULE("_curses", "_C_API"), + KNOWN_CAPSULE("datetime", "datetime_CAPI"), + { NULL, NULL }, + }; + known_capsule *known = &known_capsules[0]; + +#define FAIL(x) { error = (x); goto exit; } + +#define CHECK_DESTRUCTOR \ + if (capsule_error) { \ + FAIL(capsule_error); \ + } \ + else if (!capsule_destructor_call_count) { \ + FAIL("destructor not called!"); \ + } \ + capsule_destructor_call_count = 0; \ + + object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor); + PyCapsule_SetContext(object, capsule_context); + capsule_destructor(object); + CHECK_DESTRUCTOR; + Py_DECREF(object); + CHECK_DESTRUCTOR; + + object = PyCapsule_New(known, "ignored", NULL); + PyCapsule_SetPointer(object, capsule_pointer); + PyCapsule_SetName(object, capsule_name); + PyCapsule_SetDestructor(object, capsule_destructor); + PyCapsule_SetContext(object, capsule_context); + capsule_destructor(object); + CHECK_DESTRUCTOR; + /* intentionally access using the wrong name */ + pointer2 = PyCapsule_GetPointer(object, "the wrong name"); + if (!PyErr_Occurred()) { + FAIL("PyCapsule_GetPointer should have failed but did not!"); + } + PyErr_Clear(); + if (pointer2) { + if (pointer2 == capsule_pointer) { + FAIL("PyCapsule_GetPointer should not have" + " returned the internal pointer!"); + } else { + FAIL("PyCapsule_GetPointer should have " + "returned NULL pointer but did not!"); + } + } + PyCapsule_SetDestructor(object, NULL); + Py_DECREF(object); + if (capsule_destructor_call_count) { + FAIL("destructor called when it should not have been!"); + } + + for (known = &known_capsules[0]; known->module != NULL; known++) { + /* yeah, ordinarily I wouldn't do this either, + but it's fine for this test harness. + */ + static char buffer[256]; +#undef FAIL +#define FAIL(x) \ + { \ + sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \ + x, known->module, known->attribute); \ + error = buffer; \ + goto exit; \ + } \ + + PyObject *module = PyImport_ImportModule(known->module); + if (module) { + pointer = PyCapsule_Import(known->name, 0); + if (!pointer) { + Py_DECREF(module); + FAIL("PyCapsule_GetPointer returned NULL unexpectedly!"); + } + object = PyObject_GetAttrString(module, known->attribute); + if (!object) { + Py_DECREF(module); + return NULL; + } + pointer2 = PyCapsule_GetPointer(object, + "weebles wobble but they don't fall down"); + if (!PyErr_Occurred()) { + Py_DECREF(object); + Py_DECREF(module); + FAIL("PyCapsule_GetPointer should have failed but did not!"); + } + PyErr_Clear(); + if (pointer2) { + Py_DECREF(module); + Py_DECREF(object); + if (pointer2 == pointer) { + FAIL("PyCapsule_GetPointer should not have" + " returned its internal pointer!"); + } else { + FAIL("PyCapsule_GetPointer should have" + " returned NULL pointer but did not!"); + } + } + Py_DECREF(object); + Py_DECREF(module); + } + else + PyErr_Clear(); + } + + exit: + if (error) { + return raiseTestError("test_capsule", error); + } + Py_RETURN_NONE; +#undef FAIL +} + /* This is here to provide a docstring for test_descr. */ static PyObject * test_with_docstring(PyObject *self) @@ -1539,6 +1690,7 @@ static PyMethodDef TestMethods[] = { {"_test_thread_state", test_thread_state, METH_VARARGS}, {"_pending_threadfunc", pending_threadfunc, METH_VARARGS}, #endif + {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, {"traceback_print", traceback_print, METH_VARARGS}, {"code_newempty", code_newempty, METH_VARARGS}, {"make_exception_with_doc", (PyCFunction)make_exception_with_doc, |