Commit bdfb50f3 by Dean Moldovan

Move tests from test_issues.cpp/py into appropriate files

parent 44e9a4e6
...@@ -40,7 +40,6 @@ set(PYBIND11_TEST_FILES ...@@ -40,7 +40,6 @@ set(PYBIND11_TEST_FILES
test_eval.cpp test_eval.cpp
test_exceptions.cpp test_exceptions.cpp
test_inheritance.cpp test_inheritance.cpp
test_issues.cpp
test_kwargs_and_defaults.cpp test_kwargs_and_defaults.cpp
test_methods_and_attributes.cpp test_methods_and_attributes.cpp
test_modules.cpp test_modules.cpp
...@@ -59,7 +58,7 @@ set(PYBIND11_TEST_FILES ...@@ -59,7 +58,7 @@ set(PYBIND11_TEST_FILES
) )
# Invoking cmake with something like: # 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: # lets you override the tests that get compiled and run. You can restore to all tests with:
# cmake -DPYBIND11_TEST_OVERRIDE= .. # cmake -DPYBIND11_TEST_OVERRIDE= ..
if (PYBIND11_TEST_OVERRIDE) if (PYBIND11_TEST_OVERRIDE)
......
...@@ -187,4 +187,23 @@ test_initializer copy_move_policies([](py::module &m) { ...@@ -187,4 +187,23 @@ test_initializer copy_move_policies([](py::module &m) {
static PrivateOpNew x{}; static PrivateOpNew x{};
return x; return x;
}, py::return_value_policy::reference); }, 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);
}); });
...@@ -109,3 +109,13 @@ def test_private_op_new(): ...@@ -109,3 +109,13 @@ def test_private_op_new():
assert "the object is neither movable nor copyable" in str(excinfo.value) assert "the object is neither movable nor copyable" in str(excinfo.value)
assert m.private_op_new_reference().value == 1 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
...@@ -120,4 +120,24 @@ test_initializer inheritance([](py::module &m) { ...@@ -120,4 +120,24 @@ test_initializer inheritance([](py::module &m) {
py::class_<MismatchBase2>(m, "MismatchBase2"); py::class_<MismatchBase2>(m, "MismatchBase2");
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, MismatchBase2>(m, "MismatchDerived2"); 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);
}); });
...@@ -76,3 +76,16 @@ def test_holder(): ...@@ -76,3 +76,16 @@ def test_holder():
assert str(excinfo.value) == ("generic_type: type \"MismatchDerived2\" has a " assert str(excinfo.value) == ("generic_type: type \"MismatchDerived2\" has a "
"non-default holder type while its base " "non-default holder type while its base "
"\"MismatchBase2\" does not") "\"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)
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)
...@@ -170,6 +170,13 @@ int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; } ...@@ -170,6 +170,13 @@ int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; } 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; } 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) { test_initializer methods_and_attributes([](py::module &m) {
py::class_<ExampleMandA> emna(m, "ExampleMandA"); py::class_<ExampleMandA> emna(m, "ExampleMandA");
emna.def(py::init<>()) emna.def(py::init<>())
...@@ -315,6 +322,8 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -315,6 +322,8 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); 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("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 /// Issue/PR #648: bad arg default debugging output
#if !defined(NDEBUG) #if !defined(NDEBUG)
...@@ -344,4 +353,11 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -344,4 +353,11 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("ok_none4", &none4, py::arg().none(true)); m.def("ok_none4", &none4, py::arg().none(true));
m.def("ok_none5", &none5); 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) + "]"; }
);
}); });
...@@ -304,9 +304,9 @@ def test_cyclic_gc(): ...@@ -304,9 +304,9 @@ def test_cyclic_gc():
def test_noconvert_args(msg): 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")) == """ assert msg(a.f("hi")) == """
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
""" """
...@@ -330,15 +330,15 @@ def test_noconvert_args(msg): ...@@ -330,15 +330,15 @@ def test_noconvert_args(msg):
""" """
assert (a.h("arg 1") == assert (a.h("arg 1") ==
"loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = 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 ArgInspector2 argument WITH conversion allowed. Argument value = A1
loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2
""" """
assert floats_preferred(4) == 2.0 assert m.floats_preferred(4) == 2.0
assert floats_only(4.0) == 2.0 assert m.floats_only(4.0) == 2.0
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
floats_only(4) m.floats_only(4)
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
floats_only(): incompatible function arguments. The following argument types are supported: floats_only(): incompatible function arguments. The following argument types are supported:
1. (f: float) -> float 1. (f: float) -> float
...@@ -346,6 +346,27 @@ def test_noconvert_args(msg): ...@@ -346,6 +346,27 @@ def test_noconvert_args(msg):
Invoked with: 4 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): def test_bad_arg_default(msg):
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
...@@ -371,7 +392,7 @@ def test_bad_arg_default(msg): ...@@ -371,7 +392,7 @@ def test_bad_arg_default(msg):
) )
def test_accepts_none(): def test_accepts_none(msg):
from pybind11_tests import (NoneTester, from pybind11_tests import (NoneTester,
no_none1, no_none2, no_none3, no_none4, no_none5, no_none1, no_none2, no_none3, no_none4, no_none5,
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5) ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
...@@ -407,9 +428,32 @@ def test_accepts_none(): ...@@ -407,9 +428,32 @@ def test_accepts_none():
# The first one still raises because you can't pass None as a lvalue reference arg: # The first one still raises because you can't pass None as a lvalue reference arg:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert ok_none1(None) == -1 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: # The rest take the argument as pointer or holder, and accept None:
assert ok_none2(None) == -1 assert ok_none2(None) == -1
assert ok_none3(None) == -1 assert ok_none3(None) == -1
assert ok_none4(None) == -1 assert ok_none4(None) == -1
assert ok_none5(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'
"""
...@@ -55,4 +55,47 @@ test_initializer modules([](py::module &m) { ...@@ -55,4 +55,47 @@ test_initializer modules([](py::module &m) {
.def_readwrite("a2", &B::a2); .def_readwrite("a2", &B::a2);
m.attr("OD") = py::module::import("collections").attr("OrderedDict"); 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;
});
}); });
...@@ -61,3 +61,10 @@ def test_pydoc(): ...@@ -61,3 +61,10 @@ def test_pydoc():
assert pybind11_tests.__doc__ == "pybind11 test module" assert pybind11_tests.__doc__ == "pybind11 test module"
assert pydoc.text.docmodule(pybind11_tests) 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() == []
...@@ -56,7 +56,38 @@ private: ...@@ -56,7 +56,38 @@ private:
float x, y; 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") py::class_<Vector2>(m, "Vector2")
.def(py::init<float, float>()) .def(py::init<float, float>())
.def(py::self + py::self) .def(py::self + py::self)
...@@ -81,4 +112,41 @@ test_initializer operator_overloading([](py::module &m) { ...@@ -81,4 +112,41 @@ test_initializer operator_overloading([](py::module &m) {
; ;
m.attr("Vector") = m.attr("Vector2"); 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; });
}); });
import pytest
from pybind11_tests import ConstructorStats
def test_operator_overloading(): def test_operator_overloading():
from pybind11_tests import Vector2, Vector, ConstructorStats from pybind11_tests.operators import Vector2, Vector
v1 = Vector2(1, 2) v1 = Vector2(1, 2)
v2 = Vector(3, -1) v2 = Vector(3, -1)
...@@ -51,3 +55,53 @@ def test_operator_overloading(): ...@@ -51,3 +55,53 @@ def test_operator_overloading():
assert cstats.move_constructions >= 10 assert cstats.move_constructions >= 10
assert cstats.copy_assignments == 0 assert cstats.copy_assignments == 0
assert cstats.move_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()
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <pybind11/complex.h>
#ifdef _WIN32 #ifdef _WIN32
# include <io.h> # include <io.h>
...@@ -215,6 +216,17 @@ std::vector<std::reference_wrapper<IncrIntWrapper>> incr_int_wrappers() { ...@@ -215,6 +216,17 @@ std::vector<std::reference_wrapper<IncrIntWrapper>> incr_int_wrappers() {
return r; 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) { test_initializer python_types([](py::module &m) {
/* No constructor is explicitly defined below. An exception is raised when /* No constructor is explicitly defined below. An exception is raised when
trying to construct it directly from Python */ trying to construct it directly from Python */
...@@ -501,6 +513,8 @@ test_initializer python_types([](py::module &m) { ...@@ -501,6 +513,8 @@ test_initializer python_types([](py::module &m) {
); );
}); });
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 // 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 /*𝐀*/; 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; 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 @@ test_initializer python_types([](py::module &m) { ...@@ -661,6 +675,19 @@ test_initializer python_types([](py::module &m) {
return l; 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) #if defined(_MSC_VER)
......
...@@ -452,6 +452,12 @@ def test_implicit_casting(): ...@@ -452,6 +452,12 @@ def test_implicit_casting():
assert z['l'] == [3, 6, 9, 12, 15] 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(): def test_unicode_conversion():
"""Tests unicode conversion and error reporting.""" """Tests unicode conversion and error reporting."""
import pybind11_tests import pybind11_tests
...@@ -699,3 +705,11 @@ def test_reference_wrapper(): ...@@ -699,3 +705,11 @@ def test_reference_wrapper():
assert refwrap_iiw(IncrIntWrapper(5)) == 5 assert refwrap_iiw(IncrIntWrapper(5)) == 5
assert refwrap_call_iiw(IncrIntWrapper(10), refwrap_iiw) == [10, 10, 10, 10] 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)"
...@@ -351,4 +351,14 @@ test_initializer sequences_and_iterators([](py::module &pm) { ...@@ -351,4 +351,14 @@ test_initializer sequences_and_iterators([](py::module &pm) {
m.def("tuple_iterator", [](py::tuple x) { return test_random_access_iterator(x); }); 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("list_iterator", [](py::list x) { return test_random_access_iterator(x); });
m.def("sequence_iterator", [](py::sequence 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); });
}); });
...@@ -147,3 +147,20 @@ def test_python_iterator_in_cpp(): ...@@ -147,3 +147,20 @@ def test_python_iterator_in_cpp():
assert all(m.tuple_iterator(tuple(r))) assert all(m.tuple_iterator(tuple(r)))
assert all(m.list_iterator(list(r))) assert all(m.list_iterator(list(r)))
assert all(m.sequence_iterator(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()))
...@@ -259,6 +259,18 @@ public: ...@@ -259,6 +259,18 @@ public:
PYBIND11_DECLARE_HOLDER_TYPE(T, CustomUniquePtr<T>); 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) { test_initializer smart_ptr_and_references([](py::module &pm) {
auto m = pm.def_submodule("smart_ptr"); auto m = pm.def_submodule("smart_ptr");
...@@ -309,4 +321,21 @@ test_initializer smart_ptr_and_references([](py::module &pm) { ...@@ -309,4 +321,21 @@ test_initializer smart_ptr_and_references([](py::module &pm) {
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder") py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
.def(py::init<>()) .def(py::init<>())
.def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {}); .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;
});
}); });
...@@ -234,3 +234,15 @@ def test_smart_ptr_from_default(): ...@@ -234,3 +234,15 @@ def test_smart_ptr_from_default():
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
HeldByDefaultHolder.load_shared_ptr(instance) HeldByDefaultHolder.load_shared_ptr(instance)
assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo) 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()
...@@ -311,6 +311,16 @@ void initialize_inherited_virtuals(py::module &m) { ...@@ -311,6 +311,16 @@ void initialize_inherited_virtuals(py::module &m) {
}; };
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) { test_initializer virtual_functions([](py::module &m) {
py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt") py::class_<ExampleVirt, PyExampleVirt>(m, "ExampleVirt")
...@@ -341,4 +351,51 @@ test_initializer virtual_functions([](py::module &m) { ...@@ -341,4 +351,51 @@ test_initializer virtual_functions([](py::module &m) {
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>); m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
initialize_inherited_virtuals(m); 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);
}); });
...@@ -257,3 +257,42 @@ def test_move_support(): ...@@ -257,3 +257,42 @@ def test_move_support():
assert mv_stats.copy_constructions == 1 assert mv_stats.copy_constructions == 1
assert nc_stats.move_constructions >= 0 assert nc_stats.move_constructions >= 0
assert mv_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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment