diff options
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r-- | Modules/_testcapimodule.c | 79 |
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 */ }; |