Adding unit tests: 2 x test_std_make_shared_factory

Completes unit test coverage for the changed code in smart_holder_type_casters.h.
This commit is contained in:
Ralf W. Grosse-Kunstleve 2021-06-28 17:35:06 -07:00 committed by Ralf W. Grosse-Kunstleve
parent 1b752f56c1
commit e2108546e1
5 changed files with 41 additions and 7 deletions

View File

@ -413,21 +413,20 @@ struct smart_holder_type_caster_load {
if (std::get_deleter<shared_ptr_dec_ref_deleter>(hld.vptr) != nullptr) { if (std::get_deleter<shared_ptr_dec_ref_deleter>(hld.vptr) != nullptr) {
// This code is reachable only if there are multiple registered_instances for the // This code is reachable only if there are multiple registered_instances for the
// same pointee. // same pointee.
// SMART_HOLDER_WIP: keep weak_ref? // SMART_HOLDER_WIP: keep weak_ref
std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>(); std::shared_ptr<void> void_shd_ptr = hld.template as_shared_ptr<void>();
return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr); return std::shared_ptr<T>(void_shd_ptr, type_raw_ptr);
} }
if (!pybindit::memory::type_has_shared_from_this(type_raw_ptr)) { if (!pybindit::memory::type_has_shared_from_this(type_raw_ptr)) {
// SMART_HOLDER_WIP: unit test coverage. // SMART_HOLDER_WIP: keep weak_ref
// SMART_HOLDER_WIP: keep weak_ref?
auto self = reinterpret_cast<PyObject *>(load_impl.loaded_v_h.inst); auto self = reinterpret_cast<PyObject *>(load_impl.loaded_v_h.inst);
Py_INCREF(self); Py_INCREF(self);
return std::shared_ptr<T>(type_raw_ptr, shared_ptr_dec_ref_deleter{self}); return std::shared_ptr<T>(type_raw_ptr, shared_ptr_dec_ref_deleter{self});
} }
if (hld.vptr_is_external_shared_ptr) { if (hld.vptr_is_external_shared_ptr) {
// SMART_HOLDER_WIP: unit test coverage. pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: not "
pybind11_fail("smart_holder_type_casters loaded_as_shared_ptr failure: external " "implemented: trampoline-self-life-support for external shared_ptr "
"shared_ptr for type with shared_from_this."); "to type inheriting from std::enable_shared_from_this.");
} }
pybind11_fail("smart_holder_type_casters: loaded_as_shared_ptr failure: internal " pybind11_fail("smart_holder_type_casters: loaded_as_shared_ptr failure: internal "
"inconsistency."); "inconsistency.");

View File

@ -103,7 +103,10 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(SftSharedPtrStash)
TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) { TEST_SUBMODULE(class_sh_trampoline_shared_from_this, m) {
py::classh<Sft, SftTrampoline>(m, "Sft") py::classh<Sft, SftTrampoline>(m, "Sft")
.def(py::init<std::string>()) .def(py::init<const std::string &>())
.def(py::init([](const std::string &history, int) {
return std::make_shared<SftTrampoline>(history);
}))
.def_readonly("history", &Sft::history) .def_readonly("history", &Sft::history)
// This leads to multiple entries in registered_instances: // This leads to multiple entries in registered_instances:
.def(py::init([](const std::shared_ptr<Sft> &existing) { return existing; })); .def(py::init([](const std::shared_ptr<Sft> &existing) { return existing; }));

View File

@ -171,3 +171,20 @@ def test_multiple_registered_instances_for_same_pointee():
else: else:
assert not hasattr(obj_pt, "attachment_in_dict") assert not hasattr(obj_pt, "attachment_in_dict")
break # Comment out for manual leak checking (use `top` command). break # Comment out for manual leak checking (use `top` command).
def test_std_make_shared_factory():
class PySftMakeShared(m.Sft):
def __init__(self, history):
super(PySftMakeShared, self).__init__(history, 0)
obj = PySftMakeShared("PySftMakeShared")
assert obj.history == "PySftMakeShared"
with pytest.raises(RuntimeError) as exc_info:
m.pass_through_shd_ptr(obj)
assert (
str(exc_info.value)
== "smart_holder_type_casters loaded_as_shared_ptr failure: not implemented:"
" trampoline-self-life-support for external shared_ptr to type inheriting"
" from std::enable_shared_from_this."
)

View File

@ -26,7 +26,10 @@ struct SpBase {
virtual ~SpBase() = default; virtual ~SpBase() = default;
}; };
std::shared_ptr<SpBase> pass_through_shd_ptr(const std::shared_ptr<SpBase> &obj) { return obj; }
struct PySpBase : SpBase { struct PySpBase : SpBase {
using SpBase::SpBase;
bool is_base_used() override { PYBIND11_OVERRIDE(bool, SpBase, is_base_used); } bool is_base_used() override { PYBIND11_OVERRIDE(bool, SpBase, is_base_used); }
}; };
@ -61,9 +64,12 @@ TEST_SUBMODULE(class_sh_trampoline_shared_ptr_cpp_arg, m) {
py::classh<SpBase, PySpBase>(m, "SpBase") py::classh<SpBase, PySpBase>(m, "SpBase")
.def(py::init<>()) .def(py::init<>())
.def(py::init([](int) { return std::make_shared<PySpBase>(); }))
.def("is_base_used", &SpBase::is_base_used) .def("is_base_used", &SpBase::is_base_used)
.def("has_python_instance", &SpBase::has_python_instance); .def("has_python_instance", &SpBase::has_python_instance);
m.def("pass_through_shd_ptr", pass_through_shd_ptr);
py::classh<SpBaseTester>(m, "SpBaseTester") py::classh<SpBaseTester>(m, "SpBaseTester")
.def(py::init<>()) .def(py::init<>())
.def("get_object", &SpBaseTester::get_object) .def("get_object", &SpBaseTester::get_object)

View File

@ -131,3 +131,12 @@ def test_infinite():
while True: while True:
tester.set_object(m.SpBase()) tester.set_object(m.SpBase())
return # Comment out for manual leak checking (use `top` command). return # Comment out for manual leak checking (use `top` command).
def test_std_make_shared_factory():
class PyChild(m.SpBase):
def __init__(self):
super(PyChild, self).__init__(0)
obj = PyChild()
assert m.pass_through_shd_ptr(obj) is obj