summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r--Modules/_testcapimodule.c152
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,