summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r--Modules/_testcapimodule.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 9d4517c..8b63f9c 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3372,6 +3372,84 @@ error:
}
+static PyObject *
+test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
+{
+ // Create a new heap type, create an instance of this type, and delete the
+ // type. This object supports weak references.
+ PyObject *new_type = PyObject_CallFunction((PyObject*)&PyType_Type,
+ "s(){}", "TypeName");
+ if (new_type == NULL) {
+ return NULL;
+ }
+ PyObject *obj = PyObject_CallNoArgs(new_type);
+ Py_DECREF(new_type);
+ if (obj == NULL) {
+ return NULL;
+ }
+ Py_ssize_t refcnt = Py_REFCNT(obj);
+
+ // test PyWeakref_NewRef(), reference is alive
+ PyObject *weakref = PyWeakref_NewRef(obj, NULL);
+ if (weakref == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+ assert(PyWeakref_Check(weakref));
+ assert(PyWeakref_CheckRefExact(weakref));
+ assert(PyWeakref_CheckRefExact(weakref));
+ assert(Py_REFCNT(obj) == refcnt);
+
+ // test PyWeakref_GetRef(), reference is alive
+ PyObject *ref1;
+ assert(PyWeakref_GetRef(weakref, &ref1) == 0);
+ assert(ref1 == obj);
+ assert(Py_REFCNT(obj) == (refcnt + 1));
+ Py_DECREF(ref1);
+
+ // test PyWeakref_GetObject(), reference is alive
+ PyObject *ref2 = PyWeakref_GetObject(weakref);
+ assert(ref2 == obj);
+
+ // test PyWeakref_GET_OBJECT(), reference is alive
+ PyObject *ref3 = PyWeakref_GET_OBJECT(weakref);
+ assert(ref3 == obj);
+
+ // delete the referenced object
+ assert(Py_REFCNT(obj) == 1);
+ Py_DECREF(obj);
+
+ // test PyWeakref_GET_OBJECT(), reference is dead
+ assert(PyWeakref_GET_OBJECT(weakref) == Py_None);
+
+ // test PyWeakref_GetRef(), reference is dead
+ PyObject *ref4 = Py_True; // marker to check that value was set
+ assert(PyWeakref_GetRef(weakref, &ref4) == 0);
+ assert(ref4 == NULL);
+
+ // None is not a weak reference object
+ PyObject *invalid_weakref = Py_None;
+ assert(!PyWeakref_Check(invalid_weakref));
+ assert(!PyWeakref_CheckRefExact(invalid_weakref));
+ assert(!PyWeakref_CheckRefExact(invalid_weakref));
+
+ // test PyWeakref_GetRef(), invalid type
+ assert(!PyErr_Occurred());
+ PyObject *ref5 = Py_True; // marker to check that value was set
+ assert(PyWeakref_GetRef(invalid_weakref, &ref5) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+ assert(ref5 == NULL);
+
+ // test PyWeakref_GetObject(), invalid type
+ assert(PyWeakref_GetObject(invalid_weakref) == NULL);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+
+ Py_RETURN_NONE;
+}
+
+
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
@@ -3516,6 +3594,7 @@ static PyMethodDef TestMethods[] = {
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
{"test_atexit", test_atexit, METH_NOARGS},
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
+ {"test_weakref_capi", test_weakref_capi, METH_NOARGS},
{NULL, NULL} /* sentinel */
};