Simplify tests by replacing output capture with asserts where possible

The C++ part of the test code is modified to achieve this. As a result,
this kind of test:

```python
with capture:
    kw_func1(5, y=10)
assert capture == "kw_func(x=5, y=10)"
```

can be replaced with a simple:

`assert kw_func1(5, y=10) == "x=5, y=10"`
This commit is contained in:
Dean Moldovan 2016-08-12 22:28:31 +02:00
parent a0c1ccf0a9
commit 665e8804f3
18 changed files with 258 additions and 405 deletions

View File

@ -12,18 +12,16 @@
#include <pybind11/functional.h>
bool test_callback1(py::object func) {
func();
return false;
py::object test_callback1(py::object func) {
return func();
}
int test_callback2(py::object func) {
py::object result = func("Hello", 'x', true, 5);
return result.cast<int>();
py::tuple test_callback2(py::object func) {
return func("Hello", 'x', true, 5);
}
void test_callback3(const std::function<int(int)> &func) {
cout << "func(43) = " << func(43)<< std::endl;
std::string test_callback3(const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43));
}
std::function<int(int)> test_callback4() {
@ -37,27 +35,24 @@ py::cpp_function test_callback5() {
int dummy_function(int i) { return i + 1; }
int dummy_function2(int i, int j) { return i + j; }
std::function<int(int)> roundtrip(std::function<int(int)> f) {
if (!f)
std::cout << "roundtrip (got None).." << std::endl;
else
std::cout << "roundtrip.." << std::endl;
std::function<int(int)> roundtrip(std::function<int(int)> f, bool expect_none = false) {
if (expect_none && f) {
throw std::runtime_error("Expected None to be converted to empty std::function");
}
return f;
}
void test_dummy_function(const std::function<int(int)> &f) {
std::string test_dummy_function(const std::function<int(int)> &f) {
using fn_type = int (*)(int);
auto result = f.target<fn_type>();
if (!result) {
std::cout << "could not convert to a function pointer." << std::endl;
auto r = f(1);
std::cout << "eval(1) = " << r << std::endl;
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
} else if (*result == dummy_function) {
std::cout << "argument matches dummy_function" << std::endl;
auto r = (*result)(1);
std::cout << "eval(1) = " << r << std::endl;
return "matches dummy_function: eval(1) = " + std::to_string(r);
} else {
std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl;
return "argument does NOT match dummy_function. This should never happen!";
}
}
@ -96,7 +91,7 @@ void init_ex_callbacks(py::module &m) {
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
m.def("dummy_function", &dummy_function);
m.def("dummy_function2", &dummy_function2);
m.def("roundtrip", &roundtrip);
m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false);
m.def("test_dummy_function", &test_dummy_function);
// Export the payload constructor statistics for testing purposes:
m.def("payload_cstats", &ConstructorStats::get<Payload>);

View File

@ -1,70 +1,51 @@
import pytest
def test_inheritance(capture, msg):
from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_print
def test_inheritance(msg):
from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species
roger = Rabbit('Rabbit')
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
with capture:
pet_print(roger)
assert capture == "Rabbit is a parrot"
assert pet_name_species(roger) == "Rabbit is a parrot"
polly = Pet('Polly', 'parrot')
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
with capture:
pet_print(polly)
assert capture == "Polly is a parrot"
assert pet_name_species(polly) == "Polly is a parrot"
molly = Dog('Molly')
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
with capture:
pet_print(molly)
assert capture == "Molly is a dog"
assert pet_name_species(molly) == "Molly is a dog"
with capture:
dog_bark(molly)
assert capture == "Woof!"
assert dog_bark(molly) == "Woof!"
with pytest.raises(TypeError) as excinfo:
dog_bark(polly)
assert msg(excinfo.value) == """
Incompatible function arguments. The following argument types are supported:
1. (arg0: m.Dog) -> None
1. (arg0: m.Dog) -> str
Invoked with: <m.Pet object at 0>
"""
def test_callbacks(capture):
def test_callbacks():
from functools import partial
from pybind11_tests import (test_callback1, test_callback2, test_callback3,
test_callback4, test_callback5)
def func1():
print('Callback function 1 called!')
return "func1"
def func2(a, b, c, d):
print('Callback function 2 called : {}, {}, {}, {}'.format(a, b, c, d))
return d
return "func2", a, b, c, d
def func3(a):
print('Callback function 3 called : {}'.format(a))
return "func3({})".format(a)
with capture:
assert test_callback1(func1) is False
assert capture == "Callback function 1 called!"
with capture:
assert test_callback2(func2) == 5
assert capture == "Callback function 2 called : Hello, x, True, 5"
with capture:
assert test_callback1(partial(func2, "Hello", "from", "partial", "object")) is False
assert capture == "Callback function 2 called : Hello, from, partial, object"
with capture:
assert test_callback1(partial(func3, "Partial object with one argument")) is False
assert capture == "Callback function 3 called : Partial object with one argument"
with capture:
test_callback3(lambda i: i + 1)
assert capture == "func(43) = 44"
assert test_callback1(func1) == "func1"
assert test_callback2(func2) == ("func2", "Hello", "x", True, 5)
assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
assert test_callback1(partial(func3, "partial")) == "func3(partial)"
assert test_callback3(lambda i: i + 1) == "func(43) = 44"
f = test_callback4()
assert f(43) == 44
@ -82,49 +63,27 @@ def test_lambda_closure_cleanup():
assert cstats.move_constructions >= 1
def test_cpp_function_roundtrip(capture):
def test_cpp_function_roundtrip():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip
with capture:
test_dummy_function(dummy_function)
assert capture == """
argument matches dummy_function
eval(1) = 2
"""
with capture:
test_dummy_function(roundtrip(dummy_function))
assert capture == """
roundtrip..
argument matches dummy_function
eval(1) = 2
"""
with capture:
assert roundtrip(None) is None
assert capture == "roundtrip (got None).."
with capture:
test_dummy_function(lambda x: x + 2)
assert capture == """
could not convert to a function pointer.
eval(1) = 3
"""
assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2"
assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2"
assert roundtrip(None, expect_none=True) is None
assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3"
with capture:
with pytest.raises(TypeError) as excinfo:
test_dummy_function(dummy_function2)
assert "Incompatible function arguments" in str(excinfo.value)
assert capture == "could not convert to a function pointer."
with capture:
with pytest.raises(TypeError) as excinfo:
test_dummy_function(lambda x, y: x + y)
assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
"takes exactly 2 arguments"))
assert capture == "could not convert to a function pointer."
def test_function_signatures(doc):
from pybind11_tests import test_callback3, test_callback4
assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> None"
assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]"

View File

@ -27,27 +27,24 @@ public:
};
static EMode test_function(EMode mode) {
std::cout << "ExampleWithEnum::test_function(enum=" << mode << ")" << std::endl;
return mode;
}
};
bool test_function1() {
std::cout << "test_function()" << std::endl;
return false;
std::string test_function1() {
return "test_function()";
}
void test_function2(EMyEnumeration k) {
std::cout << "test_function(enum=" << k << ")" << std::endl;
std::string test_function2(EMyEnumeration k) {
return "test_function(enum=" + std::to_string(k) + ")";
}
float test_function3(int i) {
std::cout << "test_function(" << i << ")" << std::endl;
return (float) i / 2.f;
std::string test_function3(int i) {
return "test_function(" + std::to_string(i) + ")";
}
void test_ecenum(ECMyEnum z) {
std::cout << "test_ecenum(ECMyEnum::" << (z == ECMyEnum::Two ? "Two" : "Three") << ")" << std::endl;
std::string test_ecenum(ECMyEnum z) {
return "test_ecenum(ECMyEnum::" + std::string(z == ECMyEnum::Two ? "Two" : "Three") + ")";
}
py::bytes return_bytes() {
@ -55,10 +52,14 @@ py::bytes return_bytes() {
return std::string(data, 4);
}
void print_bytes(py::bytes bytes) {
std::string value = (std::string) bytes;
for (size_t i = 0; i < value.length(); ++i)
std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl;
std::string print_bytes(py::bytes bytes) {
std::string ret = "bytes[";
const auto value = static_cast<std::string>(bytes);
for (size_t i = 0; i < value.length(); ++i) {
ret += std::to_string(static_cast<int>(value[i])) + " ";
}
ret.back() = ']';
return ret;
}
void init_ex_constants_and_functions(py::module &m) {

View File

@ -7,20 +7,13 @@ def test_constants():
assert some_constant == 14
def test_function_overloading(capture):
def test_function_overloading():
from pybind11_tests import EMyEnumeration, test_function
with capture:
assert test_function() is False
assert test_function(7) == 3.5
assert test_function(EMyEnumeration.EFirstEntry) is None
assert test_function(EMyEnumeration.ESecondEntry) is None
assert capture == """
test_function()
test_function(7)
test_function(enum=1)
test_function(enum=2)
"""
assert test_function() == "test_function()"
assert test_function(7) == "test_function(7)"
assert test_function(EMyEnumeration.EFirstEntry) == "test_function(enum=1)"
assert test_function(EMyEnumeration.ESecondEntry) == "test_function(enum=2)"
def test_unscoped_enum():
@ -39,16 +32,12 @@ def test_unscoped_enum():
assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry"
def test_scoped_enum(capture):
def test_scoped_enum():
from pybind11_tests import ECMyEnum, test_ecenum
with capture:
test_ecenum(ECMyEnum.Three)
assert capture == "test_ecenum(ECMyEnum::Three)"
assert test_ecenum(ECMyEnum.Three) == "test_ecenum(ECMyEnum::Three)"
z = ECMyEnum.Two
with capture:
test_ecenum(z)
assert capture == "test_ecenum(ECMyEnum::Two)"
assert test_ecenum(z) == "test_ecenum(ECMyEnum::Two)"
# expected TypeError exceptions for scoped enum ==/!= int comparisons
with pytest.raises(TypeError):
@ -57,7 +46,7 @@ def test_scoped_enum(capture):
assert z != 3
def test_implicit_conversion(capture):
def test_implicit_conversion():
from pybind11_tests import ExampleWithEnum
assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode"
@ -67,11 +56,8 @@ def test_implicit_conversion(capture):
first = ExampleWithEnum.EFirstMode
second = ExampleWithEnum.ESecondMode
with capture:
f(first)
assert capture == "ExampleWithEnum::test_function(enum=1)"
assert f(first) == 1
with capture:
assert f(first) == f(first)
assert not f(first) != f(first)
@ -83,48 +69,16 @@ def test_implicit_conversion(capture):
assert f(first) != int(f(second))
assert not f(first) == int(f(second))
assert capture == """
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
"""
with capture:
# noinspection PyDictCreation
x = {f(first): 1, f(second): 2}
x[f(first)] = 3
x[f(second)] = 4
assert capture == """
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
ExampleWithEnum::test_function(enum=1)
ExampleWithEnum::test_function(enum=2)
"""
# Hashing test
assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"
def test_bytes(capture):
def test_bytes():
from pybind11_tests import return_bytes, print_bytes
with capture:
print_bytes(return_bytes())
assert capture == """
bytes[0]=1
bytes[1]=0
bytes[2]=2
bytes[3]=0
"""
assert print_bytes(return_bytes()) == "bytes[1 0 2 0]"

View File

@ -23,7 +23,7 @@ private:
class Dog : public Pet {
public:
Dog(const std::string &name) : Pet(name, "dog") {}
void bark() const { std::cout << "Woof!" << std::endl; }
std::string bark() const { return "Woof!"; }
};
class Rabbit : public Pet {
@ -31,12 +31,12 @@ public:
Rabbit(const std::string &name) : Pet(name, "parrot") {}
};
void pet_print(const Pet &pet) {
std::cout << pet.name() + " is a " + pet.species() << std::endl;
std::string pet_name_species(const Pet &pet) {
return pet.name() + " is a " + pet.species();
}
void dog_bark(const Dog &dog) {
dog.bark();
std::string dog_bark(const Dog &dog) {
return dog.bark();
}
@ -59,7 +59,7 @@ void init_ex_inheritance(py::module &m) {
py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
.def(py::init<std::string>());
m.def("pet_print", pet_print);
m.def("pet_name_species", pet_name_species);
m.def("dog_bark", dog_bark);
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());

View File

@ -34,19 +34,20 @@ void init_issues(py::module &m) {
#endif
// #137: const char* isn't handled properly
m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
m2.def("print_cchar", [](const char *s) { return std::string(s); });
// #150: char bindings broken
m2.def("print_char", [](char c) { std::cout << c << std::endl; });
m2.def("print_char", [](char c) { return std::string(1, c); });
// #159: virtual function dispatch has problems with similar-named functions
struct Base { virtual void dispatch(void) const {
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 void dispatch(void) const {
PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
virtual std::string dispatch() const {
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
}
};
@ -54,7 +55,7 @@ void init_issues(py::module &m) {
.def(py::init<>())
.def("dispatch", &Base::dispatch);
m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });
m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
struct Placeholder { int i; Placeholder(int i) : i(i) { } };
@ -171,7 +172,7 @@ void init_issues(py::module &m) {
.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("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
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; });
}

View File

@ -2,24 +2,22 @@ import pytest
import gc
def test_regressions(capture):
def test_regressions():
from pybind11_tests.issues import print_cchar, print_char
with capture:
print_cchar("const char *") # #137: const char* isn't handled properly
assert capture == "const char *"
with capture:
print_char("c") # #150: char bindings broken
assert capture == "c"
# #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(capture, msg):
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):
print("Yay..")
return "Yay.."
class PyClass2(DispatchIssue):
def dispatch(self):
@ -28,12 +26,10 @@ def test_dispatch_issue(capture, msg):
assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
p = PyClass1()
dispatch_issue_go(p)
return dispatch_issue_go(p)
b = PyClass2()
with capture:
dispatch_issue_go(b)
assert capture == "Yay.."
assert dispatch_issue_go(b) == "Yay.."
def test_reference_wrapper():
@ -127,36 +123,26 @@ def test_str_issue(capture, msg):
"""
def test_nested(capture):
def test_nested():
""" #328: first member in a class can't be used in operators"""
from pybind11_tests.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC
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
with capture:
print_NestA(a)
print_NestA(b.a)
print_NestA(c.b.a)
print_NestB(b)
print_NestB(c.b)
print_NestC(c)
assert capture == """
13
103
1003
3
1
35
"""
assert get_NestC(c) == 35
abase = a.as_base()
assert abase.value == -2

View File

@ -10,13 +10,14 @@
#include "pybind11_tests.h"
#include <pybind11/stl.h>
void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; }
std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }
void kw_func4(const std::vector<int> &entries) {
std::cout << "kw_func4: ";
std::string kw_func4(const std::vector<int> &entries) {
std::string ret = "{";
for (int i : entries)
std::cout << i << " ";
std::cout << endl;
ret += std::to_string(i) + " ";
ret.back() = '}';
return ret;
}
py::object call_kw_func(py::function f) {

View File

@ -5,77 +5,51 @@ from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, ca
def test_function_signatures(doc):
assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> None"
assert doc(kw_func1) == "kw_func1(x: int, y: int) -> None"
assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> None"
assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str"
assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None"
assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> None"
assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> None"
assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> None"
assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
assert doc(args_function) == "args_function(*args) -> None"
assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None"
assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None"
assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None"
def test_named_arguments(capture, msg):
with capture:
kw_func1(5, 10)
assert capture == "kw_func(x=5, y=10)"
with capture:
kw_func1(5, y=10)
assert capture == "kw_func(x=5, y=10)"
with capture:
kw_func1(y=10, x=5)
assert capture == "kw_func(x=5, y=10)"
def test_named_arguments(msg):
assert kw_func0(5, 10) == "x=5, y=10"
with capture:
kw_func2()
assert capture == "kw_func(x=100, y=200)"
with capture:
kw_func2(5)
assert capture == "kw_func(x=5, y=200)"
with capture:
kw_func2(x=5)
assert capture == "kw_func(x=5, y=200)"
with capture:
kw_func2(y=10)
assert capture == "kw_func(x=100, y=10)"
with capture:
kw_func2(5, 10)
assert capture == "kw_func(x=5, y=10)"
with capture:
kw_func2(x=5, y=10)
assert capture == "kw_func(x=5, y=10)"
assert kw_func1(5, 10) == "x=5, y=10"
assert kw_func1(5, y=10) == "x=5, y=10"
assert kw_func1(y=10, x=5) == "x=5, y=10"
assert kw_func2() == "x=100, y=200"
assert kw_func2(5) == "x=5, y=200"
assert kw_func2(x=5) == "x=5, y=200"
assert kw_func2(y=10) == "x=100, y=10"
assert kw_func2(5, 10) == "x=5, y=10"
assert kw_func2(x=5, y=10) == "x=5, y=10"
with pytest.raises(TypeError) as excinfo:
# noinspection PyArgumentList
kw_func2(x=5, y=10, z=12)
assert msg(excinfo.value) == """
Incompatible function arguments. The following argument types are supported:
1. (x: int=100, y: int=200) -> None
1. (x: int=100, y: int=200) -> str
Invoked with:
"""
with capture:
kw_func4()
assert capture == "kw_func4: 13 17"
with capture:
kw_func4(myList=[1, 2, 3])
assert capture == "kw_func4: 1 2 3"
assert kw_func4() == "{13 17}"
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
with capture:
kw_func_udl(x=5, y=10)
assert capture == "kw_func(x=5, y=10)"
with capture:
kw_func_udl_z(x=5)
assert capture == "kw_func(x=5, y=0)"
assert kw_func_udl(x=5, y=10) == "x=5, y=10"
assert kw_func_udl_z(x=5) == "x=5, y=0"
def test_arg_and_kwargs(capture):
with capture:
call_kw_func(kw_func2)
assert capture == "kw_func(x=1234, y=5678)"
assert call_kw_func(kw_func2) == "x=1234, y=5678"
with capture:
args_function('arg1_value', 'arg2_value', 3)
assert capture.unordered == """

View File

@ -11,8 +11,8 @@
#include "pybind11_tests.h"
#include "constructor_stats.h"
void submodule_func() {
std::cout << "submodule_func()" << std::endl;
std::string submodule_func() {
return "submodule_func()";
}
class A {

View File

@ -1,14 +1,12 @@
def test_nested_modules(capture):
def test_nested_modules():
import pybind11_tests
from pybind11_tests.submodule import submodule_func
assert pybind11_tests.__name__ == "pybind11_tests"
assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule"
with capture:
submodule_func()
assert capture == "submodule_func()"
assert submodule_func() == "submodule_func()"
def test_reference_internal():

View File

@ -8,7 +8,6 @@
*/
#include "pybind11_tests.h"
#include <pybind11/numpy.h>
#ifdef __GNUC__
@ -139,29 +138,48 @@ py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
}
template <typename S>
void print_recarray(py::array_t<S, 0> arr) {
auto req = arr.request();
auto ptr = static_cast<S*>(req.ptr);
for (size_t i = 0; i < req.size; i++)
std::cout << ptr[i] << std::endl;
py::list print_recarray(py::array_t<S, 0> arr) {
const auto req = arr.request();
const auto ptr = static_cast<S*>(req.ptr);
auto l = py::list();
for (size_t i = 0; i < req.size; i++) {
std::stringstream ss;
ss << ptr[i];
l.append(py::str(ss.str()));
}
return l;
}
void print_format_descriptors() {
std::cout << py::format_descriptor<SimpleStruct>::format() << std::endl;
std::cout << py::format_descriptor<PackedStruct>::format() << std::endl;
std::cout << py::format_descriptor<NestedStruct>::format() << std::endl;
std::cout << py::format_descriptor<PartialStruct>::format() << std::endl;
std::cout << py::format_descriptor<PartialNestedStruct>::format() << std::endl;
std::cout << py::format_descriptor<StringStruct>::format() << std::endl;
py::list print_format_descriptors() {
const auto fmts = {
py::format_descriptor<SimpleStruct>::format(),
py::format_descriptor<PackedStruct>::format(),
py::format_descriptor<NestedStruct>::format(),
py::format_descriptor<PartialStruct>::format(),
py::format_descriptor<PartialNestedStruct>::format(),
py::format_descriptor<StringStruct>::format()
};
auto l = py::list();
for (const auto &fmt : fmts) {
l.append(py::cast(fmt));
}
return l;
}
void print_dtypes() {
std::cout << (std::string) py::dtype::of<SimpleStruct>().str() << std::endl;
std::cout << (std::string) py::dtype::of<PackedStruct>().str() << std::endl;
std::cout << (std::string) py::dtype::of<NestedStruct>().str() << std::endl;
std::cout << (std::string) py::dtype::of<PartialStruct>().str() << std::endl;
std::cout << (std::string) py::dtype::of<PartialNestedStruct>().str() << std::endl;
std::cout << (std::string) py::dtype::of<StringStruct>().str() << std::endl;
py::list print_dtypes() {
const auto dtypes = {
py::dtype::of<SimpleStruct>().str(),
py::dtype::of<PackedStruct>().str(),
py::dtype::of<NestedStruct>().str(),
py::dtype::of<PartialStruct>().str(),
py::dtype::of<PartialNestedStruct>().str(),
py::dtype::of<StringStruct>().str()
};
auto l = py::list();
for (const auto &s : dtypes) {
l.append(s);
}
return l;
}
py::array_t<int32_t, 0> test_array_ctors(int i) {

View File

@ -13,39 +13,35 @@ packed_dtype = np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')])
@pytest.requires_numpy
def test_format_descriptors(capture):
def test_format_descriptors():
from pybind11_tests import get_format_unbound, print_format_descriptors
with pytest.raises(RuntimeError) as excinfo:
get_format_unbound()
assert 'unsupported buffer format' in str(excinfo.value)
with capture:
print_format_descriptors()
assert capture == """
T{=?:x:3x=I:y:=f:z:}
T{=?:x:=I:y:=f:z:}
T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}
T{=?:x:3x=I:y:=f:z:12x}
T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}
T{=3s:a:=3s:b:}
"""
assert print_format_descriptors() == [
"T{=?:x:3x=I:y:=f:z:}",
"T{=?:x:=I:y:=f:z:}",
"T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}",
"T{=?:x:3x=I:y:=f:z:12x}",
"T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}",
"T{=3s:a:=3s:b:}"
]
@pytest.requires_numpy
def test_dtype(capture):
def test_dtype():
from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods
with capture:
print_dtypes()
assert capture == """
{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}
[('x', '?'), ('y', '<u4'), ('z', '<f4')]
[('a', {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}), ('b', [('x', '?'), ('y', '<u4'), ('z', '<f4')])]
{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}
{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}
[('a', 'S3'), ('b', 'S3')]
"""
assert print_dtypes() == [
"{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}",
"[('x', '?'), ('y', '<u4'), ('z', '<f4')]",
"[('a', {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}), ('b', [('x', '?'), ('y', '<u4'), ('z', '<f4')])]",
"{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}",
"{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}",
"[('a', 'S3'), ('b', 'S3')]"
]
d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
'offsets': [1, 10], 'itemsize': 20})
@ -58,7 +54,7 @@ def test_dtype(capture):
@pytest.requires_numpy
def test_recarray(capture):
def test_recarray():
from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
print_rec_simple, print_rec_packed, print_rec_nested,
create_rec_partial, create_rec_partial_nested)
@ -77,21 +73,17 @@ def test_recarray(capture):
assert_equal(arr, elements, packed_dtype)
if dtype == simple_dtype:
with capture:
print_rec_simple(arr)
assert capture == """
s:0,0,0
s:1,1,1.5
s:0,2,3
"""
assert print_rec_simple(arr) == [
"s:0,0,0",
"s:1,1,1.5",
"s:0,2,3"
]
else:
with capture:
print_rec_packed(arr)
assert capture == """
p:0,0,0
p:1,1,1.5
p:0,2,3
"""
assert print_rec_packed(arr) == [
"p:0,0,0",
"p:1,1,1.5",
"p:0,2,3"
]
nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
@ -104,13 +96,11 @@ def test_recarray(capture):
assert_equal(arr, [((False, 0, 0.0), (True, 1, 1.5)),
((True, 1, 1.5), (False, 2, 3.0)),
((False, 2, 3.0), (True, 3, 4.5))], nested_dtype)
with capture:
print_rec_nested(arr)
assert capture == """
n:a=s:0,0,0;b=p:1,1,1.5
n:a=s:1,1,1.5;b=p:0,2,3
n:a=s:0,2,3;b=p:1,3,4.5
"""
assert print_rec_nested(arr) == [
"n:a=s:0,0,0;b=p:1,1,1.5",
"n:a=s:1,1,1.5;b=p:0,2,3",
"n:a=s:0,2,3;b=p:1,3,4.5"
]
arr = create_rec_partial(3)
assert str(arr.dtype) == "{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}"
@ -142,19 +132,17 @@ def test_array_constructors():
@pytest.requires_numpy
def test_string_array(capture):
def test_string_array():
from pybind11_tests import create_string_array, print_string_array
arr = create_string_array(True)
assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
with capture:
print_string_array(arr)
assert capture == """
a='',b=''
a='a',b='a'
a='ab',b='ab'
a='abc',b='abc'
"""
assert print_string_array(arr) == [
"a='',b=''",
"a='a',b='a'",
"a='ab',b='ab'",
"a='abc',b='abc'"
]
dtype = arr.dtype
assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']

View File

@ -35,7 +35,7 @@ void init_ex_numpy_vectorize(py::module &m) {
m.def("vectorized_func3", py::vectorize(my_func3));
/// Numpy function which only accepts specific data types
m.def("selective_func", [](py::array_t<int, py::array::c_style>) { std::cout << "Int branch taken." << std::endl; });
m.def("selective_func", [](py::array_t<float, py::array::c_style>) { std::cout << "Float branch taken." << std::endl; });
m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { std::cout << "Complex float branch taken." << std::endl; });
m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; });
m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
}

View File

@ -59,18 +59,12 @@ def test_vectorize(capture):
@pytest.requires_numpy
def test_type_selection(capture):
def test_type_selection():
from pybind11_tests import selective_func
with capture:
selective_func(np.array([1], dtype=np.int32))
selective_func(np.array([1.0], dtype=np.float32))
selective_func(np.array([1.0j], dtype=np.complex64))
assert capture == """
Int branch taken.
Float branch taken.
Complex float branch taken.
"""
assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
@pytest.requires_numpy

View File

@ -38,21 +38,21 @@ void init_ex_opaque_types(py::module &m) {
.def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
m.def("print_opaque_list", [](const StringList &l) {
std::cout << "Opaque list: [";
std::string ret = "Opaque list: [";
bool first = true;
for (auto entry : l) {
if (!first)
std::cout << ", ";
std::cout << entry;
ret += ", ";
ret += entry;
first = false;
}
std::cout << "]" << std::endl;
return ret + "]";
});
m.def("return_void_ptr", []() { return (void *) 0x1234; });
m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
m.def("return_null_str", []() { return (char *) nullptr; });
m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
StringList *result = new StringList();

View File

@ -1,64 +1,48 @@
import pytest
def test_string_list(capture):
def test_string_list():
from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list
l = StringList()
l.push_back("Element 1")
l.push_back("Element 2")
with capture:
print_opaque_list(l)
assert capture == "Opaque list: [Element 1, Element 2]"
assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]"
assert l.back() == "Element 2"
for i, k in enumerate(l, start=1):
assert k == "Element {}".format(i)
l.pop_back()
with capture:
print_opaque_list(l)
assert capture == "Opaque list: [Element 1]"
assert print_opaque_list(l) == "Opaque list: [Element 1]"
cvp = ClassWithSTLVecProperty()
with capture:
print_opaque_list(cvp.stringList)
assert capture == "Opaque list: []"
assert print_opaque_list(cvp.stringList) == "Opaque list: []"
cvp.stringList = l
cvp.stringList.push_back("Element 3")
with capture:
print_opaque_list(cvp.stringList)
assert capture == "Opaque list: [Element 1, Element 3]"
assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
def test_pointers(capture, msg):
from pybind11_tests import (return_void_ptr, print_void_ptr, ExampleMandA,
print_opaque_list, return_null_str, print_null_str,
def test_pointers(msg):
from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA,
print_opaque_list, return_null_str, get_null_str_value,
return_unique_ptr, ConstructorStats)
with capture:
print_void_ptr(return_void_ptr())
assert capture == "Got void ptr : 0x1234"
with capture:
print_void_ptr(ExampleMandA()) # Should also work for other C++ types
assert "Got void ptr" in capture
assert get_void_ptr_value(return_void_ptr()) == 0x1234
assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types
assert ConstructorStats.get(ExampleMandA).alive() == 0
with pytest.raises(TypeError) as excinfo:
print_void_ptr([1, 2, 3]) # This should not work
get_void_ptr_value([1, 2, 3]) # This should not work
assert msg(excinfo.value) == """
Incompatible function arguments. The following argument types are supported:
1. (arg0: capsule) -> None
1. (arg0: capsule) -> int
Invoked with: [1, 2, 3]
"""
assert return_null_str() is None
with capture:
print_null_str(return_null_str())
assert capture == "Got null str : 0x0"
assert get_null_str_value(return_null_str()) is not None
ptr = return_unique_ptr()
assert "StringList" in repr(ptr)
with capture:
print_opaque_list(ptr)
assert capture == "Opaque list: [some value]"
assert print_opaque_list(ptr) == "Opaque list: [some value]"

View File

@ -173,7 +173,7 @@ def test_inheriting_repeat(capture):
assert obj.lucky_number() == -4.25
def test_move_support(capture, msg):
def test_move_support(capture):
from pybind11_tests import NCVirt, NonCopyable, Movable
class NCVirtExt(NCVirt):