aboutsummaryrefslogtreecommitdiff
path: root/tests/test_type_caster_pyobject_ptr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_type_caster_pyobject_ptr.cpp')
-rw-r--r--tests/test_type_caster_pyobject_ptr.cpp130
1 files changed, 130 insertions, 0 deletions
diff --git a/tests/test_type_caster_pyobject_ptr.cpp b/tests/test_type_caster_pyobject_ptr.cpp
new file mode 100644
index 00000000..1667ea12
--- /dev/null
+++ b/tests/test_type_caster_pyobject_ptr.cpp
@@ -0,0 +1,130 @@
+#include <pybind11/functional.h>
+#include <pybind11/stl.h>
+#include <pybind11/type_caster_pyobject_ptr.h>
+
+#include "pybind11_tests.h"
+
+#include <cstddef>
+#include <vector>
+
+namespace {
+
+std::vector<PyObject *> make_vector_pyobject_ptr(const py::object &ValueHolder) {
+ std::vector<PyObject *> vec_obj;
+ for (int i = 1; i < 3; i++) {
+ vec_obj.push_back(ValueHolder(i * 93).release().ptr());
+ }
+ // This vector now owns the refcounts.
+ return vec_obj;
+}
+
+} // namespace
+
+TEST_SUBMODULE(type_caster_pyobject_ptr, m) {
+ m.def("cast_from_pyobject_ptr", []() {
+ PyObject *ptr = PyLong_FromLongLong(6758L);
+ return py::cast(ptr, py::return_value_policy::take_ownership);
+ });
+ m.def("cast_handle_to_pyobject_ptr", [](py::handle obj) {
+ auto rc1 = obj.ref_count();
+ auto *ptr = py::cast<PyObject *>(obj);
+ auto rc2 = obj.ref_count();
+ if (rc2 != rc1 + 1) {
+ return -1;
+ }
+ return 100 - py::reinterpret_steal<py::object>(ptr).attr("value").cast<int>();
+ });
+ m.def("cast_object_to_pyobject_ptr", [](py::object obj) {
+ py::handle hdl = obj;
+ auto rc1 = hdl.ref_count();
+ auto *ptr = py::cast<PyObject *>(std::move(obj));
+ auto rc2 = hdl.ref_count();
+ if (rc2 != rc1) {
+ return -1;
+ }
+ return 300 - py::reinterpret_steal<py::object>(ptr).attr("value").cast<int>();
+ });
+ m.def("cast_list_to_pyobject_ptr", [](py::list lst) {
+ // This is to cover types implicitly convertible to object.
+ py::handle hdl = lst;
+ auto rc1 = hdl.ref_count();
+ auto *ptr = py::cast<PyObject *>(std::move(lst));
+ auto rc2 = hdl.ref_count();
+ if (rc2 != rc1) {
+ return -1;
+ }
+ return 400 - static_cast<int>(py::len(py::reinterpret_steal<py::list>(ptr)));
+ });
+
+ m.def(
+ "return_pyobject_ptr",
+ []() { return PyLong_FromLongLong(2314L); },
+ py::return_value_policy::take_ownership);
+ m.def("pass_pyobject_ptr", [](PyObject *ptr) {
+ return 200 - py::reinterpret_borrow<py::object>(ptr).attr("value").cast<int>();
+ });
+
+ m.def("call_callback_with_object_return",
+ [](const std::function<py::object(int)> &cb, int value) { return cb(value); });
+ m.def(
+ "call_callback_with_pyobject_ptr_return",
+ [](const std::function<PyObject *(int)> &cb, int value) { return cb(value); },
+ py::return_value_policy::take_ownership);
+ m.def(
+ "call_callback_with_pyobject_ptr_arg",
+ [](const std::function<int(PyObject *)> &cb, py::handle obj) { return cb(obj.ptr()); },
+ py::arg("cb"), // This triggers return_value_policy::automatic_reference
+ py::arg("obj"));
+
+ m.def("cast_to_pyobject_ptr_nullptr", [](bool set_error) {
+ if (set_error) {
+ PyErr_SetString(PyExc_RuntimeError, "Reflective of healthy error handling.");
+ }
+ PyObject *ptr = nullptr;
+ py::cast(ptr);
+ });
+
+ m.def("cast_to_pyobject_ptr_non_nullptr_with_error_set", []() {
+ PyErr_SetString(PyExc_RuntimeError, "Reflective of unhealthy error handling.");
+ py::cast(Py_None);
+ });
+
+ m.def("pass_list_pyobject_ptr", [](const std::vector<PyObject *> &vec_obj) {
+ int acc = 0;
+ for (const auto &ptr : vec_obj) {
+ acc = acc * 1000 + py::reinterpret_borrow<py::object>(ptr).attr("value").cast<int>();
+ }
+ return acc;
+ });
+
+ m.def("return_list_pyobject_ptr_take_ownership",
+ make_vector_pyobject_ptr,
+ // Ownership is transferred one-by-one when the vector is converted to a Python list.
+ py::return_value_policy::take_ownership);
+
+ m.def("return_list_pyobject_ptr_reference",
+ make_vector_pyobject_ptr,
+ // Ownership is not transferred.
+ py::return_value_policy::reference);
+
+ m.def("dec_ref_each_pyobject_ptr", [](const std::vector<PyObject *> &vec_obj) {
+ std::size_t i = 0;
+ for (; i < vec_obj.size(); i++) {
+ py::handle h(vec_obj[i]);
+ if (static_cast<std::size_t>(h.ref_count()) < 2) {
+ break; // Something is badly wrong.
+ }
+ h.dec_ref();
+ }
+ return i;
+ });
+
+ m.def("pass_pyobject_ptr_and_int", [](PyObject *, int) {});
+
+#ifdef PYBIND11_NO_COMPILE_SECTION // Change to ifndef for manual testing.
+ {
+ PyObject *ptr = nullptr;
+ (void) py::cast(*ptr);
+ }
+#endif
+}