Move tests from test_issues.cpp/py into appropriate files
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d40c25a..be223f5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -40,7 +40,6 @@
test_eval.cpp
test_exceptions.cpp
test_inheritance.cpp
- test_issues.cpp
test_kwargs_and_defaults.cpp
test_methods_and_attributes.cpp
test_modules.cpp
@@ -59,7 +58,7 @@
)
# Invoking cmake with something like:
-# cmake -DPYBIND11_TEST_OVERRIDE="test_issues.cpp;test_picking.cpp" ..
+# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_picking.cpp" ..
# lets you override the tests that get compiled and run. You can restore to all tests with:
# cmake -DPYBIND11_TEST_OVERRIDE= ..
if (PYBIND11_TEST_OVERRIDE)
diff --git a/tests/test_copy_move.cpp b/tests/test_copy_move.cpp
index 90ca6da..e80cdb8 100644
--- a/tests/test_copy_move.cpp
+++ b/tests/test_copy_move.cpp
@@ -187,4 +187,23 @@
static PrivateOpNew x{};
return x;
}, py::return_value_policy::reference);
+
+ // #389: rvp::move should fall-through to copy on non-movable objects
+ struct MoveIssue1 {
+ int v;
+ MoveIssue1(int v) : v{v} {}
+ MoveIssue1(const MoveIssue1 &c) = default;
+ MoveIssue1(MoveIssue1 &&) = delete;
+ };
+
+ struct MoveIssue2 {
+ int v;
+ MoveIssue2(int v) : v{v} {}
+ MoveIssue2(MoveIssue2 &&) = default;
+ };
+
+ py::class_<MoveIssue1>(m, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
+ py::class_<MoveIssue2>(m, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
+ m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move);
+ m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
});
diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py
index 386fce7..452f6fb 100644
--- a/tests/test_copy_move.py
+++ b/tests/test_copy_move.py
@@ -109,3 +109,13 @@
assert "the object is neither movable nor copyable" in str(excinfo.value)
assert m.private_op_new_reference().value == 1
+
+
+def test_move_fallback():
+ """#389: rvp::move should fall-through to copy on non-movable objects"""
+ from pybind11_tests import get_moveissue1, get_moveissue2
+
+ m2 = get_moveissue2(2)
+ assert m2.value == 2
+ m1 = get_moveissue1(1)
+ assert m1.value == 1
diff --git a/tests/test_inheritance.cpp b/tests/test_inheritance.cpp
index c19f58d..6129b3f 100644
--- a/tests/test_inheritance.cpp
+++ b/tests/test_inheritance.cpp
@@ -120,4 +120,24 @@
py::class_<MismatchBase2>(m, "MismatchBase2");
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(m, "MismatchDerived2");
});
+
+ // #511: problem with inheritance + overwritten def_static
+ struct MyBase {
+ static std::unique_ptr<MyBase> make() {
+ return std::unique_ptr<MyBase>(new MyBase());
+ }
+ };
+
+ struct MyDerived : MyBase {
+ static std::unique_ptr<MyDerived> make() {
+ return std::unique_ptr<MyDerived>(new MyDerived());
+ }
+ };
+
+ py::class_<MyBase>(m, "MyBase")
+ .def_static("make", &MyBase::make);
+
+ py::class_<MyDerived, MyBase>(m, "MyDerived")
+ .def_static("make", &MyDerived::make)
+ .def_static("make2", &MyDerived::make);
});
diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py
index d1f537d..40630ae 100644
--- a/tests/test_inheritance.py
+++ b/tests/test_inheritance.py
@@ -76,3 +76,16 @@
assert str(excinfo.value) == ("generic_type: type \"MismatchDerived2\" has a "
"non-default holder type while its base "
"\"MismatchBase2\" does not")
+
+
+def test_inheritance_override_def_static():
+ """#511: problem with inheritance + overwritten def_static"""
+ from pybind11_tests import MyBase, MyDerived
+
+ b = MyBase.make()
+ d1 = MyDerived.make2()
+ d2 = MyDerived.make()
+
+ assert isinstance(b, MyBase)
+ assert isinstance(d1, MyDerived)
+ assert isinstance(d2, MyDerived)
diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp
deleted file mode 100644
index 6d88d9a..0000000
--- a/tests/test_issues.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- tests/test_issues.cpp -- collection of testcases for miscellaneous issues
-
- Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
-
- All rights reserved. Use of this source code is governed by a
- BSD-style license that can be found in the LICENSE file.
-*/
-
-#include "pybind11_tests.h"
-#include "constructor_stats.h"
-#include <pybind11/stl.h>
-#include <pybind11/operators.h>
-#include <pybind11/complex.h>
-
-#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
-struct NestABase { int value = -2; TRACKERS(NestABase) };
-struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
-struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
-struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
-
-/// #393
-class OpTest1 {};
-class OpTest2 {};
-
-OpTest1 operator+(const OpTest1 &, const OpTest1 &) {
- py::print("Add OpTest1 with OpTest1");
- return OpTest1();
-}
-OpTest2 operator+(const OpTest2 &, const OpTest2 &) {
- py::print("Add OpTest2 with OpTest2");
- return OpTest2();
-}
-OpTest2 operator+(const OpTest2 &, const OpTest1 &) {
- py::print("Add OpTest2 with OpTest1");
- return OpTest2();
-}
-
-// #461
-class Dupe1 {
-public:
- Dupe1(int v) : v_{v} {}
- int get_value() const { return v_; }
-private:
- int v_;
-};
-class Dupe2 {};
-class Dupe3 {};
-class DupeException : public std::runtime_error {};
-
-// #478
-template <typename T> class custom_unique_ptr {
-public:
- custom_unique_ptr() { print_default_created(this); }
- custom_unique_ptr(T *ptr) : _ptr{ptr} { print_created(this, ptr); }
- custom_unique_ptr(custom_unique_ptr<T> &&move) : _ptr{move._ptr} { move._ptr = nullptr; print_move_created(this); }
- custom_unique_ptr &operator=(custom_unique_ptr<T> &&move) { print_move_assigned(this); if (_ptr) destruct_ptr(); _ptr = move._ptr; move._ptr = nullptr; return *this; }
- custom_unique_ptr(const custom_unique_ptr<T> &) = delete;
- void operator=(const custom_unique_ptr<T> ©) = delete;
- ~custom_unique_ptr() { print_destroyed(this); if (_ptr) destruct_ptr(); }
-private:
- T *_ptr = nullptr;
- void destruct_ptr() { delete _ptr; }
-};
-PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
-
-/// Issue #528: templated constructor
-struct TplConstrClass {
- template <typename T> TplConstrClass(const T &arg) : str{arg} {}
- std::string str;
- bool operator==(const TplConstrClass &t) const { return t.str == str; }
-};
-namespace std {
-template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass &t) const { return std::hash<std::string>()(t.str); } };
-}
-
-void init_issues(py::module &m) {
- py::module m2 = m.def_submodule("issues");
-
- // #137: const char* isn't handled properly
- m2.def("print_cchar", [](const char *s) { return std::string(s); });
-
- // #150: char bindings broken
- m2.def("print_char", [](char c) { return std::string(1, c); });
-
- // #159: virtual function dispatch has problems with similar-named functions
- struct Base { virtual std::string dispatch() const {
- /* for some reason MSVC2015 can't compile this if the function is pure virtual */
- return {};
- }; };
-
- struct DispatchIssue : Base {
- virtual std::string dispatch() const {
- PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
- }
- };
-
- py::class_<Base, DispatchIssue>(m2, "DispatchIssue")
- .def(py::init<>())
- .def("dispatch", &Base::dispatch);
-
- m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
-
- struct Placeholder { int i; Placeholder(int i) : i(i) { } };
-
- py::class_<Placeholder>(m2, "Placeholder")
- .def(py::init<int>())
- .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; });
-
- // #181: iterator passthrough did not compile
- m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
- return py::make_iterator(std::begin(s), std::end(s));
- });
-
- // #187: issue involving std::shared_ptr<> return value policy & garbage collection
- struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
- struct ElementA : ElementBase {
- ElementA(int v) : v(v) { }
- int value() { return v; }
- int v;
- };
-
- struct ElementList {
- void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
- std::vector<std::shared_ptr<ElementBase>> l;
- };
-
- py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");
-
- py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
- .def(py::init<int>())
- .def("value", &ElementA::value);
-
- py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
- .def(py::init<>())
- .def("add", &ElementList::add)
- .def("get", [](ElementList &el) {
- py::list list;
- for (auto &e : el.l)
- list.append(py::cast(e));
- return list;
- });
-
- // (no id): should not be able to pass 'None' to a reference argument
- m2.def("get_element", [](ElementA &el) { return el.value(); });
-
- // (no id): don't cast doubles to ints
- m2.def("expect_float", [](float f) { return f; });
- m2.def("expect_int", [](int i) { return i; });
-
- try {
- py::class_<Placeholder>(m2, "Placeholder");
- throw std::logic_error("Expected an exception!");
- } catch (std::runtime_error &) {
- /* All good */
- }
-
- // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
- class StrIssue {
- public:
- StrIssue(int i) : val{i} {}
- StrIssue() : StrIssue(-1) {}
- int value() const { return val; }
- private:
- int val;
- };
- py::class_<StrIssue> si(m2, "StrIssue");
- si .def(py::init<int>())
- .def(py::init<>())
- .def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; })
- ;
-
- // Issue #328: first member in a class can't be used in operators
- py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
- py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
- .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
- py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
- py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
- m2.def("get_NestA", [](const NestA &a) { return a.value; });
- m2.def("get_NestB", [](const NestB &b) { return b.value; });
- m2.def("get_NestC", [](const NestC &c) { return c.value; });
-
- // Issue 389: r_v_p::move should fall-through to copy on non-movable objects
- class MoveIssue1 {
- public:
- MoveIssue1(int v) : v{v} {}
- MoveIssue1(const MoveIssue1 &c) { v = c.v; }
- MoveIssue1(MoveIssue1 &&) = delete;
- int v;
- };
- class MoveIssue2 {
- public:
- MoveIssue2(int v) : v{v} {}
- MoveIssue2(MoveIssue2 &&) = default;
- int v;
- };
- py::class_<MoveIssue1>(m2, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
- py::class_<MoveIssue2>(m2, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
- m2.def("get_moveissue1", [](int i) -> MoveIssue1 * { return new MoveIssue1(i); }, py::return_value_policy::move);
- m2.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
-
- // Issues 392/397: overridding reference-returning functions
- class OverrideTest {
- public:
- struct A { std::string value = "hi"; };
- std::string v;
- A a;
- explicit OverrideTest(const std::string &v) : v{v} {}
- virtual std::string str_value() { return v; }
- virtual std::string &str_ref() { return v; }
- virtual A A_value() { return a; }
- virtual A &A_ref() { return a; }
- };
- class PyOverrideTest : public OverrideTest {
- public:
- using OverrideTest::OverrideTest;
- std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
- // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
- // to a python numeric value, since we only copy values in the numeric type caster:
-// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
- // But we can work around it like this:
- private:
- std::string _tmp;
- std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
- public:
- std::string &str_ref() override { return _tmp = str_ref_helper(); }
-
- A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
- A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
- };
- py::class_<OverrideTest::A>(m2, "OverrideTest_A")
- .def_readwrite("value", &OverrideTest::A::value);
- py::class_<OverrideTest, PyOverrideTest>(m2, "OverrideTest")
- .def(py::init<const std::string &>())
- .def("str_value", &OverrideTest::str_value)
-// .def("str_ref", &OverrideTest::str_ref)
- .def("A_value", &OverrideTest::A_value)
- .def("A_ref", &OverrideTest::A_ref);
-
- /// Issue 393: need to return NotSupported to ensure correct arithmetic operator behavior
- py::class_<OpTest1>(m2, "OpTest1")
- .def(py::init<>())
- .def(py::self + py::self);
-
- py::class_<OpTest2>(m2, "OpTest2")
- .def(py::init<>())
- .def(py::self + py::self)
- .def("__add__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; })
- .def("__radd__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; });
-
- // Issue 388: Can't make iterators via make_iterator() with different r/v policies
- static std::vector<int> list = { 1, 2, 3 };
- m2.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
- m2.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
-
- static std::vector<std::string> nothrows;
- // Issue 461: registering two things with the same name:
- py::class_<Dupe1>(m2, "Dupe1")
- .def("get_value", &Dupe1::get_value)
- ;
- m2.def("dupe1_factory", [](int v) { return new Dupe1(v); });
-
- py::class_<Dupe2>(m2, "Dupe2");
- py::exception<DupeException>(m2, "DupeException");
-
- try {
- m2.def("Dupe1", [](int v) { return new Dupe1(v); });
- nothrows.emplace_back("Dupe1");
- }
- catch (std::runtime_error &) {}
- try {
- py::class_<Dupe3>(m2, "dupe1_factory");
- nothrows.emplace_back("dupe1_factory");
- }
- catch (std::runtime_error &) {}
- try {
- py::exception<Dupe3>(m2, "Dupe2");
- nothrows.emplace_back("Dupe2");
- }
- catch (std::runtime_error &) {}
- try {
- m2.def("DupeException", []() { return 30; });
- nothrows.emplace_back("DupeException1");
- }
- catch (std::runtime_error &) {}
- try {
- py::class_<DupeException>(m2, "DupeException");
- nothrows.emplace_back("DupeException2");
- }
- catch (std::runtime_error &) {}
- m2.def("dupe_exception_failures", []() {
- py::list l;
- for (auto &e : nothrows) l.append(py::cast(e));
- return l;
- });
-
- /// Issue #471: shared pointer instance not dellocated
- class SharedChild : public std::enable_shared_from_this<SharedChild> {
- public:
- SharedChild() { print_created(this); }
- ~SharedChild() { print_destroyed(this); }
- };
-
- class SharedParent {
- public:
- SharedParent() : child(std::make_shared<SharedChild>()) { }
- const SharedChild &get_child() const { return *child; }
-
- private:
- std::shared_ptr<SharedChild> child;
- };
-
- py::class_<SharedChild, std::shared_ptr<SharedChild>>(m, "SharedChild");
- py::class_<SharedParent, std::shared_ptr<SharedParent>>(m, "SharedParent")
- .def(py::init<>())
- .def("get_child", &SharedParent::get_child, py::return_value_policy::reference);
-
- /// Issue/PR #478: unique ptrs constructed and freed without destruction
- class SpecialHolderObj {
- public:
- int val = 0;
- SpecialHolderObj *ch = nullptr;
- SpecialHolderObj(int v, bool make_child = true) : val{v}, ch{make_child ? new SpecialHolderObj(val+1, false) : nullptr}
- { print_created(this, val); }
- ~SpecialHolderObj() { delete ch; print_destroyed(this); }
- SpecialHolderObj *child() { return ch; }
- };
-
- py::class_<SpecialHolderObj, custom_unique_ptr<SpecialHolderObj>>(m, "SpecialHolderObj")
- .def(py::init<int>())
- .def("child", &SpecialHolderObj::child, pybind11::return_value_policy::reference_internal)
- .def_readwrite("val", &SpecialHolderObj::val)
- .def_static("holder_cstats", &ConstructorStats::get<custom_unique_ptr<SpecialHolderObj>>,
- py::return_value_policy::reference);
-
- /// Issue #484: number conversion generates unhandled exceptions
- m2.def("test_complex", [](float x) { py::print("{}"_s.format(x)); });
- m2.def("test_complex", [](std::complex<float> x) { py::print("({}, {})"_s.format(x.real(), x.imag())); });
-
- /// Issue #511: problem with inheritance + overwritten def_static
- struct MyBase {
- static std::unique_ptr<MyBase> make() {
- return std::unique_ptr<MyBase>(new MyBase());
- }
- };
-
- struct MyDerived : MyBase {
- static std::unique_ptr<MyDerived> make() {
- return std::unique_ptr<MyDerived>(new MyDerived());
- }
- };
-
- py::class_<MyBase>(m2, "MyBase")
- .def_static("make", &MyBase::make);
-
- py::class_<MyDerived, MyBase>(m2, "MyDerived")
- .def_static("make", &MyDerived::make)
- .def_static("make2", &MyDerived::make);
-
- py::dict d;
- std::string bar = "bar";
- d["str"] = bar;
- d["num"] = 3.7;
-
- /// Issue #528: templated constructor
- m2.def("tpl_constr_vector", [](std::vector<TplConstrClass> &) {});
- m2.def("tpl_constr_map", [](std::unordered_map<TplConstrClass, TplConstrClass> &) {});
- m2.def("tpl_constr_set", [](std::unordered_set<TplConstrClass> &) {});
-#if defined(PYBIND11_HAS_OPTIONAL)
- m2.def("tpl_constr_optional", [](std::optional<TplConstrClass> &) {});
-#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
- m2.def("tpl_constr_optional", [](std::experimental::optional<TplConstrClass> &) {});
-#endif
-}
-
-// MSVC workaround: trying to use a lambda here crashes MSVC
-test_initializer issues(&init_issues);
diff --git a/tests/test_issues.py b/tests/test_issues.py
deleted file mode 100644
index 08678cf..0000000
--- a/tests/test_issues.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import pytest
-from pybind11_tests import ConstructorStats
-
-
-def test_regressions():
- from pybind11_tests.issues import print_cchar, print_char
-
- # #137: const char* isn't handled properly
- assert print_cchar("const char *") == "const char *"
- # #150: char bindings broken
- assert print_char("c") == "c"
-
-
-def test_dispatch_issue(msg):
- """#159: virtual function dispatch has problems with similar-named functions"""
- from pybind11_tests.issues import DispatchIssue, dispatch_issue_go
-
- class PyClass1(DispatchIssue):
- def dispatch(self):
- return "Yay.."
-
- class PyClass2(DispatchIssue):
- def dispatch(self):
- with pytest.raises(RuntimeError) as excinfo:
- super(PyClass2, self).dispatch()
- assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
-
- p = PyClass1()
- return dispatch_issue_go(p)
-
- b = PyClass2()
- assert dispatch_issue_go(b) == "Yay.."
-
-
-def test_iterator_passthrough():
- """#181: iterator passthrough did not compile"""
- from pybind11_tests.issues import iterator_passthrough
-
- assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
-
-
-def test_shared_ptr_gc():
- """// #187: issue involving std::shared_ptr<> return value policy & garbage collection"""
- from pybind11_tests.issues import ElementList, ElementA
-
- el = ElementList()
- for i in range(10):
- el.add(ElementA(i))
- pytest.gc_collect()
- for i, v in enumerate(el.get()):
- assert i == v.value()
-
-
-def test_no_id(msg):
- from pybind11_tests.issues import get_element, expect_float, expect_int
-
- with pytest.raises(TypeError) as excinfo:
- get_element(None)
- assert msg(excinfo.value) == """
- get_element(): incompatible function arguments. The following argument types are supported:
- 1. (arg0: m.issues.ElementA) -> int
-
- Invoked with: None
- """
-
- with pytest.raises(TypeError) as excinfo:
- expect_int(5.2)
- assert msg(excinfo.value) == """
- expect_int(): incompatible function arguments. The following argument types are supported:
- 1. (arg0: int) -> int
-
- Invoked with: 5.2
- """
- assert expect_float(12) == 12
-
-
-def test_str_issue(msg):
- """Issue #283: __str__ called on uninitialized instance when constructor arguments invalid"""
- from pybind11_tests.issues import StrIssue
-
- assert str(StrIssue(3)) == "StrIssue[3]"
-
- with pytest.raises(TypeError) as excinfo:
- str(StrIssue("no", "such", "constructor"))
- assert msg(excinfo.value) == """
- __init__(): incompatible constructor arguments. The following argument types are supported:
- 1. m.issues.StrIssue(arg0: int)
- 2. m.issues.StrIssue()
-
- Invoked with: 'no', 'such', 'constructor'
- """
-
-
-def test_nested():
- """ #328: first member in a class can't be used in operators"""
- from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
-
- a = NestA()
- b = NestB()
- c = NestC()
-
- a += 10
- assert get_NestA(a) == 13
- b.a += 100
- assert get_NestA(b.a) == 103
- c.b.a += 1000
- assert get_NestA(c.b.a) == 1003
- b -= 1
- assert get_NestB(b) == 3
- c.b -= 3
- assert get_NestB(c.b) == 1
- c *= 7
- assert get_NestC(c) == 35
-
- abase = a.as_base()
- assert abase.value == -2
- a.as_base().value += 44
- assert abase.value == 42
- assert c.b.a.as_base().value == -2
- c.b.a.as_base().value += 44
- assert c.b.a.as_base().value == 42
-
- del c
- pytest.gc_collect()
- del a # Should't delete while abase is still alive
- pytest.gc_collect()
-
- assert abase.value == 42
- del abase, b
- pytest.gc_collect()
-
-
-def test_move_fallback():
- from pybind11_tests.issues import get_moveissue1, get_moveissue2
- m2 = get_moveissue2(2)
- assert m2.value == 2
- m1 = get_moveissue1(1)
- assert m1.value == 1
-
-
-def test_override_ref():
- from pybind11_tests.issues import OverrideTest
- o = OverrideTest("asdf")
-
- # Not allowed (see associated .cpp comment)
- # i = o.str_ref()
- # assert o.str_ref() == "asdf"
- assert o.str_value() == "asdf"
-
- assert o.A_value().value == "hi"
- a = o.A_ref()
- assert a.value == "hi"
- a.value = "bye"
- assert a.value == "bye"
-
-
-def test_operators_notimplemented(capture):
- from pybind11_tests.issues import OpTest1, OpTest2
- with capture:
- c1, c2 = OpTest1(), OpTest2()
- c1 + c1
- c2 + c2
- c2 + c1
- c1 + c2
- assert capture == """
- Add OpTest1 with OpTest1
- Add OpTest2 with OpTest2
- Add OpTest2 with OpTest1
- Add OpTest2 with OpTest1
- """
-
-
-def test_iterator_rvpolicy():
- """ Issue 388: Can't make iterators via make_iterator() with different r/v policies """
- from pybind11_tests.issues import make_iterator_1
- from pybind11_tests.issues import make_iterator_2
-
- assert list(make_iterator_1()) == [1, 2, 3]
- assert list(make_iterator_2()) == [1, 2, 3]
- assert not isinstance(make_iterator_1(), type(make_iterator_2()))
-
-
-def test_dupe_assignment():
- """ Issue 461: overwriting a class with a function """
- from pybind11_tests.issues import dupe_exception_failures
- assert dupe_exception_failures() == []
-
-
-def test_enable_shared_from_this_with_reference_rvp():
- """ Issue #471: shared pointer instance not dellocated """
- from pybind11_tests import SharedParent, SharedChild
-
- parent = SharedParent()
- child = parent.get_child()
-
- cstats = ConstructorStats.get(SharedChild)
- assert cstats.alive() == 1
- del child, parent
- assert cstats.alive() == 0
-
-
-def test_non_destructed_holders():
- """ Issue #478: unique ptrs constructed and freed without destruction """
- from pybind11_tests import SpecialHolderObj
-
- a = SpecialHolderObj(123)
- b = a.child()
-
- assert a.val == 123
- assert b.val == 124
-
- cstats = SpecialHolderObj.holder_cstats()
- assert cstats.alive() == 1
- del b
- assert cstats.alive() == 1
- del a
- assert cstats.alive() == 0
-
-
-def test_complex_cast(capture):
- """ Issue #484: number conversion generates unhandled exceptions """
- from pybind11_tests.issues import test_complex
-
- with capture:
- test_complex(1)
- test_complex(2j)
-
- assert capture == """
- 1.0
- (0.0, 2.0)
- """
-
-
-def test_inheritance_override_def_static():
- from pybind11_tests.issues import MyBase, MyDerived
-
- b = MyBase.make()
- d1 = MyDerived.make2()
- d2 = MyDerived.make()
-
- assert isinstance(b, MyBase)
- assert isinstance(d1, MyDerived)
- assert isinstance(d2, MyDerived)
diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp
index 81b665b..670f6c3 100644
--- a/tests/test_methods_and_attributes.cpp
+++ b/tests/test_methods_and_attributes.cpp
@@ -170,6 +170,13 @@
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }
+struct StrIssue {
+ int val = -1;
+
+ StrIssue() = default;
+ StrIssue(int i) : val{i} {}
+};
+
test_initializer methods_and_attributes([](py::module &m) {
py::class_<ExampleMandA> emna(m, "ExampleMandA");
emna.def(py::init<>())
@@ -315,6 +322,8 @@
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
+ m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
+ m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
/// Issue/PR #648: bad arg default debugging output
#if !defined(NDEBUG)
@@ -344,4 +353,11 @@
m.def("ok_none4", &none4, py::arg().none(true));
m.def("ok_none5", &none5);
+ // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
+ py::class_<StrIssue>(m, "StrIssue")
+ .def(py::init<int>())
+ .def(py::init<>())
+ .def("__str__", [](const StrIssue &si) {
+ return "StrIssue[" + std::to_string(si.val) + "]"; }
+ );
});
diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py
index 3ec3eb7..95049cf 100644
--- a/tests/test_methods_and_attributes.py
+++ b/tests/test_methods_and_attributes.py
@@ -304,9 +304,9 @@
def test_noconvert_args(msg):
- from pybind11_tests import ArgInspector, arg_inspect_func, floats_only, floats_preferred
+ import pybind11_tests as m
- a = ArgInspector()
+ a = m.ArgInspector()
assert msg(a.f("hi")) == """
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
"""
@@ -330,15 +330,15 @@
"""
assert (a.h("arg 1") ==
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1")
- assert msg(arg_inspect_func("A1", "A2")) == """
+ assert msg(m.arg_inspect_func("A1", "A2")) == """
loading ArgInspector2 argument WITH conversion allowed. Argument value = A1
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
"""
- assert floats_preferred(4) == 2.0
- assert floats_only(4.0) == 2.0
+ assert m.floats_preferred(4) == 2.0
+ assert m.floats_only(4.0) == 2.0
with pytest.raises(TypeError) as excinfo:
- floats_only(4)
+ m.floats_only(4)
assert msg(excinfo.value) == """
floats_only(): incompatible function arguments. The following argument types are supported:
1. (f: float) -> float
@@ -346,6 +346,27 @@
Invoked with: 4
"""
+ assert m.ints_preferred(4) == 2
+ assert m.ints_preferred(True) == 0
+ with pytest.raises(TypeError) as excinfo:
+ m.ints_preferred(4.0)
+ assert msg(excinfo.value) == """
+ ints_preferred(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int) -> int
+
+ Invoked with: 4.0
+ """ # noqa: E501 line too long
+
+ assert m.ints_only(4) == 2
+ with pytest.raises(TypeError) as excinfo:
+ m.ints_only(4.0)
+ assert msg(excinfo.value) == """
+ ints_only(): incompatible function arguments. The following argument types are supported:
+ 1. (i: int) -> int
+
+ Invoked with: 4.0
+ """
+
def test_bad_arg_default(msg):
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
@@ -371,7 +392,7 @@
)
-def test_accepts_none():
+def test_accepts_none(msg):
from pybind11_tests import (NoneTester,
no_none1, no_none2, no_none3, no_none4, no_none5,
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
@@ -407,9 +428,32 @@
# The first one still raises because you can't pass None as a lvalue reference arg:
with pytest.raises(TypeError) as excinfo:
assert ok_none1(None) == -1
- assert "incompatible function arguments" in str(excinfo.value)
+ assert msg(excinfo.value) == """
+ ok_none1(): incompatible function arguments. The following argument types are supported:
+ 1. (arg0: m.NoneTester) -> int
+
+ Invoked with: None
+ """
+
# The rest take the argument as pointer or holder, and accept None:
assert ok_none2(None) == -1
assert ok_none3(None) == -1
assert ok_none4(None) == -1
assert ok_none5(None) == -1
+
+
+def test_str_issue(msg):
+ """#283: __str__ called on uninitialized instance when constructor arguments invalid"""
+ from pybind11_tests import StrIssue
+
+ assert str(StrIssue(3)) == "StrIssue[3]"
+
+ with pytest.raises(TypeError) as excinfo:
+ str(StrIssue("no", "such", "constructor"))
+ assert msg(excinfo.value) == """
+ __init__(): incompatible constructor arguments. The following argument types are supported:
+ 1. m.StrIssue(arg0: int)
+ 2. m.StrIssue()
+
+ Invoked with: 'no', 'such', 'constructor'
+ """
diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp
index 50c7d84..555ae07 100644
--- a/tests/test_modules.cpp
+++ b/tests/test_modules.cpp
@@ -55,4 +55,47 @@
.def_readwrite("a2", &B::a2);
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
+
+ // Registering two things with the same name
+ m.def("duplicate_registration", []() {
+ class Dupe1 { };
+ class Dupe2 { };
+ class Dupe3 { };
+ class DupeException { };
+
+ auto dm = py::module("dummy");
+ auto failures = py::list();
+
+ py::class_<Dupe1>(dm, "Dupe1");
+ py::class_<Dupe2>(dm, "Dupe2");
+ dm.def("dupe1_factory", []() { return Dupe1(); });
+ py::exception<DupeException>(dm, "DupeException");
+
+ try {
+ py::class_<Dupe1>(dm, "Dupe1");
+ failures.append("Dupe1 class");
+ } catch (std::runtime_error &) {}
+ try {
+ dm.def("Dupe1", []() { return Dupe1(); });
+ failures.append("Dupe1 function");
+ } catch (std::runtime_error &) {}
+ try {
+ py::class_<Dupe3>(dm, "dupe1_factory");
+ failures.append("dupe1_factory");
+ } catch (std::runtime_error &) {}
+ try {
+ py::exception<Dupe3>(dm, "Dupe2");
+ failures.append("Dupe2");
+ } catch (std::runtime_error &) {}
+ try {
+ dm.def("DupeException", []() { return 30; });
+ failures.append("DupeException1");
+ } catch (std::runtime_error &) {}
+ try {
+ py::class_<DupeException>(dm, "DupeException");
+ failures.append("DupeException2");
+ } catch (std::runtime_error &) {}
+
+ return failures;
+ });
});
diff --git a/tests/test_modules.py b/tests/test_modules.py
index 2a2c794..1cb177f 100644
--- a/tests/test_modules.py
+++ b/tests/test_modules.py
@@ -61,3 +61,10 @@
assert pybind11_tests.__doc__ == "pybind11 test module"
assert pydoc.text.docmodule(pybind11_tests)
+
+
+def test_duplicate_registration():
+ """Registering two things with the same name"""
+ from pybind11_tests import duplicate_registration
+
+ assert duplicate_registration() == []
diff --git a/tests/test_operator_overloading.cpp b/tests/test_operator_overloading.cpp
index 4e868d9..cb22b12 100644
--- a/tests/test_operator_overloading.cpp
+++ b/tests/test_operator_overloading.cpp
@@ -56,7 +56,38 @@
float x, y;
};
-test_initializer operator_overloading([](py::module &m) {
+class C1 { };
+class C2 { };
+
+int operator+(const C1 &, const C1 &) { return 11; }
+int operator+(const C2 &, const C2 &) { return 22; }
+int operator+(const C2 &, const C1 &) { return 21; }
+int operator+(const C1 &, const C2 &) { return 12; }
+
+struct NestABase {
+ int value = -2;
+};
+
+struct NestA : NestABase {
+ int value = 3;
+ NestA& operator+=(int i) { value += i; return *this; }
+};
+
+struct NestB {
+ NestA a;
+ int value = 4;
+ NestB& operator-=(int i) { value -= i; return *this; }
+};
+
+struct NestC {
+ NestB b;
+ int value = 5;
+ NestC& operator*=(int i) { value *= i; return *this; }
+};
+
+test_initializer operator_overloading([](py::module &pm) {
+ auto m = pm.def_submodule("operators");
+
py::class_<Vector2>(m, "Vector2")
.def(py::init<float, float>())
.def(py::self + py::self)
@@ -81,4 +112,41 @@
;
m.attr("Vector") = m.attr("Vector2");
+
+ // #393: need to return NotSupported to ensure correct arithmetic operator behavior
+ py::class_<C1>(m, "C1")
+ .def(py::init<>())
+ .def(py::self + py::self);
+
+ py::class_<C2>(m, "C2")
+ .def(py::init<>())
+ .def(py::self + py::self)
+ .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
+ .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
+
+ // #328: first member in a class can't be used in operators
+ py::class_<NestABase>(m, "NestABase")
+ .def(py::init<>())
+ .def_readwrite("value", &NestABase::value);
+
+ py::class_<NestA>(m, "NestA")
+ .def(py::init<>())
+ .def(py::self += int())
+ .def("as_base", [](NestA &a) -> NestABase& {
+ return (NestABase&) a;
+ }, py::return_value_policy::reference_internal);
+
+ py::class_<NestB>(m, "NestB")
+ .def(py::init<>())
+ .def(py::self -= int())
+ .def_readwrite("a", &NestB::a);
+
+ py::class_<NestC>(m, "NestC")
+ .def(py::init<>())
+ .def(py::self *= int())
+ .def_readwrite("b", &NestC::b);
+
+ m.def("get_NestA", [](const NestA &a) { return a.value; });
+ m.def("get_NestB", [](const NestB &b) { return b.value; });
+ m.def("get_NestC", [](const NestC &c) { return c.value; });
});
diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py
index dd37c34..63dd546 100644
--- a/tests/test_operator_overloading.py
+++ b/tests/test_operator_overloading.py
@@ -1,5 +1,9 @@
+import pytest
+from pybind11_tests import ConstructorStats
+
+
def test_operator_overloading():
- from pybind11_tests import Vector2, Vector, ConstructorStats
+ from pybind11_tests.operators import Vector2, Vector
v1 = Vector2(1, 2)
v2 = Vector(3, -1)
@@ -51,3 +55,53 @@
assert cstats.move_constructions >= 10
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
+
+
+def test_operators_notimplemented():
+ """#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
+ from pybind11_tests.operators import C1, C2
+
+ c1, c2 = C1(), C2()
+ assert c1 + c1 == 11
+ assert c2 + c2 == 22
+ assert c2 + c1 == 21
+ assert c1 + c2 == 12
+
+
+def test_nested():
+ """#328: first member in a class can't be used in operators"""
+ from pybind11_tests.operators import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
+
+ a = NestA()
+ b = NestB()
+ c = NestC()
+
+ a += 10
+ assert get_NestA(a) == 13
+ b.a += 100
+ assert get_NestA(b.a) == 103
+ c.b.a += 1000
+ assert get_NestA(c.b.a) == 1003
+ b -= 1
+ assert get_NestB(b) == 3
+ c.b -= 3
+ assert get_NestB(c.b) == 1
+ c *= 7
+ assert get_NestC(c) == 35
+
+ abase = a.as_base()
+ assert abase.value == -2
+ a.as_base().value += 44
+ assert abase.value == 42
+ assert c.b.a.as_base().value == -2
+ c.b.a.as_base().value += 44
+ assert c.b.a.as_base().value == 42
+
+ del c
+ pytest.gc_collect()
+ del a # Should't delete while abase is still alive
+ pytest.gc_collect()
+
+ assert abase.value == 42
+ del abase, b
+ pytest.gc_collect()
diff --git a/tests/test_python_types.cpp b/tests/test_python_types.cpp
index d130af6..46a23ee 100644
--- a/tests/test_python_types.cpp
+++ b/tests/test_python_types.cpp
@@ -11,6 +11,7 @@
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/stl.h>
+#include <pybind11/complex.h>
#ifdef _WIN32
# include <io.h>
@@ -215,6 +216,17 @@
return r;
};
+/// Issue #528: templated constructor
+struct TplCtorClass {
+ template <typename T> TplCtorClass(const T &) { }
+ bool operator==(const TplCtorClass &) const { return true; }
+};
+
+namespace std {
+ template <>
+ struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
+}
+
test_initializer python_types([](py::module &m) {
/* No constructor is explicitly defined below. An exception is raised when
trying to construct it directly from Python */
@@ -501,6 +513,8 @@
);
});
+ m.def("string_roundtrip", [](const char *s) { return s; });
+
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
@@ -661,6 +675,19 @@
return l;
});
+ /// Issue #484: number conversion generates unhandled exceptions
+ m.def("test_complex", [](float x) { return "{}"_s.format(x); });
+ m.def("test_complex", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
+
+ /// Issue #528: templated constructor
+ m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
+ m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
+ m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
+#if defined(PYBIND11_HAS_OPTIONAL)
+ m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
+#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
+ m.def("tpl_constr_optional", [](std::experimental::optional<TplCtorClass> &) {});
+#endif
});
#if defined(_MSC_VER)
diff --git a/tests/test_python_types.py b/tests/test_python_types.py
index 2af9432..7932602 100644
--- a/tests/test_python_types.py
+++ b/tests/test_python_types.py
@@ -452,6 +452,12 @@
assert z['l'] == [3, 6, 9, 12, 15]
+def test_simple_string():
+ from pybind11_tests import string_roundtrip
+
+ assert string_roundtrip("const char *") == "const char *"
+
+
def test_unicode_conversion():
"""Tests unicode conversion and error reporting."""
import pybind11_tests
@@ -699,3 +705,11 @@
assert refwrap_iiw(IncrIntWrapper(5)) == 5
assert refwrap_call_iiw(IncrIntWrapper(10), refwrap_iiw) == [10, 10, 10, 10]
+
+
+def test_complex_cast():
+ """#484: number conversion generates unhandled exceptions"""
+ from pybind11_tests import test_complex
+
+ assert test_complex(1) == "1.0"
+ assert test_complex(2j) == "(0.0, 2.0)"
diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp
index c2051fa..89fde8f 100644
--- a/tests/test_sequences_and_iterators.cpp
+++ b/tests/test_sequences_and_iterators.cpp
@@ -351,4 +351,14 @@
m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); });
m.def("list_iterator", [](py::list x) { return test_random_access_iterator(x); });
m.def("sequence_iterator", [](py::sequence x) { return test_random_access_iterator(x); });
+
+ // #181: iterator passthrough did not compile
+ m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
+ return py::make_iterator(std::begin(s), std::end(s));
+ });
+
+ // #388: Can't make iterators via make_iterator() with different r/v policies
+ static std::vector<int> list = { 1, 2, 3 };
+ m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
+ m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
});
diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py
index e04c579..012e97d 100644
--- a/tests/test_sequences_and_iterators.py
+++ b/tests/test_sequences_and_iterators.py
@@ -147,3 +147,20 @@
assert all(m.tuple_iterator(tuple(r)))
assert all(m.list_iterator(list(r)))
assert all(m.sequence_iterator(r))
+
+
+def test_iterator_passthrough():
+ """#181: iterator passthrough did not compile"""
+ from pybind11_tests.sequences_and_iterators import iterator_passthrough
+
+ assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
+
+
+def test_iterator_rvp():
+ """#388: Can't make iterators via make_iterator() with different r/v policies """
+ import pybind11_tests.sequences_and_iterators as m
+
+ assert list(m.make_iterator_1()) == [1, 2, 3]
+ assert list(m.make_iterator_2()) == [1, 2, 3]
+ assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
+
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
index 1ece3d1..91239e8 100644
--- a/tests/test_smart_ptr.cpp
+++ b/tests/test_smart_ptr.cpp
@@ -259,6 +259,18 @@
PYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>);
+struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
+struct ElementA : ElementBase {
+ ElementA(int v) : v(v) { }
+ int value() { return v; }
+ int v;
+};
+
+struct ElementList {
+ void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
+ std::vector<std::shared_ptr<ElementBase>> l;
+};
+
test_initializer smart_ptr_and_references([](py::module &pm) {
auto m = pm.def_submodule("smart_ptr");
@@ -309,4 +321,21 @@
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
.def(py::init<>())
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {});
+
+ // #187: issue involving std::shared_ptr<> return value policy & garbage collection
+ py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase");
+
+ py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA")
+ .def(py::init<int>())
+ .def("value", &ElementA::value);
+
+ py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList")
+ .def(py::init<>())
+ .def("add", &ElementList::add)
+ .def("get", [](ElementList &el) {
+ py::list list;
+ for (auto &e : el.l)
+ list.append(py::cast(e));
+ return list;
+ });
});
diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py
index 7396c9f..144180d 100644
--- a/tests/test_smart_ptr.py
+++ b/tests/test_smart_ptr.py
@@ -234,3 +234,15 @@
with pytest.raises(RuntimeError) as excinfo:
HeldByDefaultHolder.load_shared_ptr(instance)
assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
+
+
+def test_shared_ptr_gc():
+ """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
+ from pybind11_tests.smart_ptr import ElementList, ElementA
+
+ el = ElementList()
+ for i in range(10):
+ el.add(ElementA(i))
+ pytest.gc_collect()
+ for i, v in enumerate(el.get()):
+ assert i == v.value()
diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp
index 5080b6d..b42f650 100644
--- a/tests/test_virtual_functions.cpp
+++ b/tests/test_virtual_functions.cpp
@@ -311,6 +311,16 @@
};
+struct Base {
+ /* for some reason MSVC2015 can't compile this if the function is pure virtual */
+ virtual std::string dispatch() const { return {}; };
+};
+
+struct DispatchIssue : Base {
+ virtual std::string dispatch() const {
+ PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
+ }
+};
test_initializer virtual_functions([](py::module &m) {
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
@@ -341,4 +351,51 @@
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
initialize_inherited_virtuals(m);
+
+ // #159: virtual function dispatch has problems with similar-named functions
+ py::class_<Base, DispatchIssue>(m, "DispatchIssue")
+ .def(py::init<>())
+ .def("dispatch", &Base::dispatch);
+
+ m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
+
+ // #392/397: overridding reference-returning functions
+ class OverrideTest {
+ public:
+ struct A { std::string value = "hi"; };
+ std::string v;
+ A a;
+ explicit OverrideTest(const std::string &v) : v{v} {}
+ virtual std::string str_value() { return v; }
+ virtual std::string &str_ref() { return v; }
+ virtual A A_value() { return a; }
+ virtual A &A_ref() { return a; }
+ };
+
+ class PyOverrideTest : public OverrideTest {
+ public:
+ using OverrideTest::OverrideTest;
+ std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
+ // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
+ // to a python numeric value, since we only copy values in the numeric type caster:
+// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
+ // But we can work around it like this:
+ private:
+ std::string _tmp;
+ std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
+ public:
+ std::string &str_ref() override { return _tmp = str_ref_helper(); }
+
+ A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
+ A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
+ };
+
+ py::class_<OverrideTest::A>(m, "OverrideTest_A")
+ .def_readwrite("value", &OverrideTest::A::value);
+ py::class_<OverrideTest, PyOverrideTest>(m, "OverrideTest")
+ .def(py::init<const std::string &>())
+ .def("str_value", &OverrideTest::str_value)
+// .def("str_ref", &OverrideTest::str_ref)
+ .def("A_value", &OverrideTest::A_value)
+ .def("A_ref", &OverrideTest::A_ref);
});
diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py
index b11c699..3ec6fc2 100644
--- a/tests/test_virtual_functions.py
+++ b/tests/test_virtual_functions.py
@@ -257,3 +257,42 @@
assert mv_stats.copy_constructions == 1
assert nc_stats.move_constructions >= 0
assert mv_stats.move_constructions >= 0
+
+
+def test_dispatch_issue(msg):
+ """#159: virtual function dispatch has problems with similar-named functions"""
+ from pybind11_tests import DispatchIssue, dispatch_issue_go
+
+ class PyClass1(DispatchIssue):
+ def dispatch(self):
+ return "Yay.."
+
+ class PyClass2(DispatchIssue):
+ def dispatch(self):
+ with pytest.raises(RuntimeError) as excinfo:
+ super(PyClass2, self).dispatch()
+ assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
+
+ p = PyClass1()
+ return dispatch_issue_go(p)
+
+ b = PyClass2()
+ assert dispatch_issue_go(b) == "Yay.."
+
+
+def test_override_ref():
+ """#392/397: overridding reference-returning functions"""
+ from pybind11_tests import OverrideTest
+
+ o = OverrideTest("asdf")
+
+ # Not allowed (see associated .cpp comment)
+ # i = o.str_ref()
+ # assert o.str_ref() == "asdf"
+ assert o.str_value() == "asdf"
+
+ assert o.A_value().value == "hi"
+ a = o.A_ref()
+ assert a.value == "hi"
+ a.value = "bye"
+ assert a.value == "bye"