Commit faec30c4 authored by Wenzel Jakob's avatar Wenzel Jakob Committed by GitHub
Browse files

Merge pull request #321 from dean0x7d/pytest

Port test suite to pytest
parents bf099587 99dbdc16
/*
example/example-sequences-and-iterators.cpp -- supporting Pythons' sequence protocol, iterators,
tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators,
etc.
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -8,8 +8,8 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "constructor-stats.h"
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/operators.h>
#include <pybind11/stl.h>
......
import pytest
def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
"""Like to math.isclose() from Python 3.5"""
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list))
def test_sequence():
from pybind11_tests import Sequence, ConstructorStats
cstats = ConstructorStats.get(Sequence)
s = Sequence(5)
assert cstats.values() == ['of size', '5']
assert "Sequence" in repr(s)
assert len(s) == 5
assert s[0] == 0 and s[3] == 0
assert 12.34 not in s
s[0], s[3] = 12.34, 56.78
assert 12.34 in s
assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
rev = reversed(s)
assert cstats.values() == ['of size', '5']
rev2 = s[::-1]
assert cstats.values() == ['of size', '5']
expected = [0, 56.78, 0, 0, 12.34]
assert allclose(rev, expected)
assert allclose(rev2, expected)
assert rev == rev2
rev[0::2] = Sequence([2.0, 2.0, 2.0])
assert cstats.values() == ['of size', '3', 'from std::vector']
assert allclose(rev, [2, 56.78, 2, 0, 2])
assert cstats.alive() == 3
del s
assert cstats.alive() == 2
del rev
assert cstats.alive() == 1
del rev2
assert cstats.alive() == 0
assert cstats.values() == []
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
assert cstats.move_constructions >= 1
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
def test_map_iterator():
from pybind11_tests import StringMap
m = StringMap({'hi': 'bye', 'black': 'white'})
assert m['hi'] == 'bye'
assert len(m) == 2
assert m['black'] == 'white'
with pytest.raises(KeyError):
assert m['orange']
m['orange'] = 'banana'
assert m['orange'] == 'banana'
expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
for k in m:
assert m[k] == expected[k]
for k, v in m.items():
assert v == expected[k]
/*
example/example-smart-ptr.cpp -- binding classes with custom reference counting,
tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
implicit conversions between types
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -8,7 +8,7 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "pybind11_tests.h"
#include "object.h"
/// Custom object with builtin reference counting (see 'object.h' for the implementation)
......
from pybind11_tests import ConstructorStats
def test_smart_ptr(capture):
# Object1
from pybind11_tests import (MyObject1, make_object_1, make_object_2,
print_object_1, print_object_2, print_object_3, print_object_4)
for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1):
assert o.getRefCount() == 1
with capture:
print_object_1(o)
print_object_2(o)
print_object_3(o)
print_object_4(o)
assert capture == "MyObject1[{i}]\n".format(i=i) * 4
from pybind11_tests import (make_myobject1_1, make_myobject1_2,
print_myobject1_1, print_myobject1_2,
print_myobject1_3, print_myobject1_4)
for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4):
print(o)
with capture:
if not isinstance(o, int):
print_object_1(o)
print_object_2(o)
print_object_3(o)
print_object_4(o)
print_myobject1_1(o)
print_myobject1_2(o)
print_myobject1_3(o)
print_myobject1_4(o)
assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
cstats = ConstructorStats.get(MyObject1)
assert cstats.alive() == 0
expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
assert cstats.values() == expected_values
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
# Object2
from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2,
make_myobject3_1, make_myobject3_2,
print_myobject2_1, print_myobject2_2,
print_myobject2_3, print_myobject2_4)
for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]):
print(o)
with capture:
print_myobject2_1(o)
print_myobject2_2(o)
print_myobject2_3(o)
print_myobject2_4(o)
assert capture == "MyObject2[{i}]\n".format(i=i) * 4
cstats = ConstructorStats.get(MyObject2)
assert cstats.alive() == 1
o = None
assert cstats.alive() == 0
assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
# Object3
from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2,
print_myobject3_3, print_myobject3_4)
for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]):
print(o)
with capture:
print_myobject3_1(o)
print_myobject3_2(o)
print_myobject3_3(o)
print_myobject3_4(o)
assert capture == "MyObject3[{i}]\n".format(i=i) * 4
cstats = ConstructorStats.get(MyObject3)
assert cstats.alive() == 1
o = None
assert cstats.alive() == 0
assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
# Object and ref
from pybind11_tests import Object, cstats_ref
cstats = ConstructorStats.get(Object)
assert cstats.alive() == 0
assert cstats.values() == []
assert cstats.default_constructions == 10
assert cstats.copy_constructions == 0
# assert cstats.move_constructions >= 0 # Doesn't invoke any
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
cstats = cstats_ref()
assert cstats.alive() == 0
assert cstats.values() == ['from pointer'] * 10
assert cstats.default_constructions == 30
assert cstats.copy_constructions == 12
# assert cstats.move_constructions >= 0 # Doesn't invoke any
assert cstats.copy_assignments == 30
assert cstats.move_assignments == 0
/*
example/example-stl-binder-vector.cpp -- Usage of stl_binders functions
tests/test_stl_binders.cpp -- Usage of stl_binders functions
Copyright (c) 2016 Sergey Lyskov
......@@ -7,7 +7,7 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "pybind11_tests.h"
#include <pybind11/stl_bind.h>
......
def test_vector_int():
from pybind11_tests import VectorInt
v_int = VectorInt([0, 0])
assert len(v_int) == 2
assert bool(v_int) is True
v_int2 = VectorInt([0, 0])
assert v_int == v_int2
v_int2[1] = 1
assert v_int != v_int2
v_int2.append(2)
v_int2.append(3)
v_int2.insert(0, 1)
v_int2.insert(0, 2)
v_int2.insert(0, 3)
assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]"
v_int.append(99)
v_int2[2:-2] = v_int
assert v_int2 == VectorInt([3, 2, 0, 0, 99, 2, 3])
del v_int2[1:3]
assert v_int2 == VectorInt([3, 0, 99, 2, 3])
del v_int2[0]
assert v_int2 == VectorInt([0, 99, 2, 3])
def test_vector_custom():
from pybind11_tests import El, VectorEl, VectorVectorEl
v_a = VectorEl()
v_a.append(El(1))
v_a.append(El(2))
assert str(v_a) == "VectorEl[El{1}, El{2}]"
vv_a = VectorVectorEl()
vv_a.append(v_a)
vv_b = vv_a[0]
assert str(vv_b) == "VectorEl[El{1}, El{2}]"
def test_vector_bool():
from pybind11_tests import VectorBool
vv_c = VectorBool()
for i in range(10):
vv_c.append(i % 2 == 0)
for i in range(10):
assert vv_c[i] == (i % 2 == 0)
assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
/*
example/example-virtual-functions.cpp -- overriding virtual functions from Python
tests/test_virtual_functions.cpp -- overriding virtual functions from Python
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -7,8 +7,8 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "constructor-stats.h"
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/functional.h>
/* This is an example class that we'll want to be able to extend from Python */
......@@ -91,7 +91,7 @@ public:
Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
Movable(const Movable &m) { value = m.value; print_copy_created(this); }
Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); }
int get_value() const { return value; }
std::string get_value() const { return std::to_string(value); }
~Movable() { print_destroyed(this); }
private:
int value;
......@@ -102,8 +102,8 @@ public:
virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
virtual Movable get_movable(int a, int b) = 0;
void print_nc(int a, int b) { std::cout << get_noncopyable(a, b).get_value() << std::endl; }
void print_movable(int a, int b) { std::cout << get_movable(a, b).get_value() << std::endl; }
std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); }
std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }
};
class NCVirtTrampoline : public NCVirt {
virtual NonCopyable get_noncopyable(int a, int b) {
......@@ -138,9 +138,11 @@ class A_Repeat {
#define A_METHODS \
public: \
virtual int unlucky_number() = 0; \
virtual void say_something(unsigned times) { \
for (unsigned i = 0; i < times; i++) std::cout << "hi"; \
std::cout << std::endl; \
virtual std::string say_something(unsigned times) { \
std::string s = ""; \
for (unsigned i = 0; i < times; ++i) \
s += "hi"; \
return s; \
}
A_METHODS
};
......@@ -148,8 +150,8 @@ class B_Repeat : public A_Repeat {
#define B_METHODS \
public: \
int unlucky_number() override { return 13; } \
void say_something(unsigned times) override { \
std::cout << "B says hi " << times << " times" << std::endl; \
std::string say_something(unsigned times) override { \
return "B says hi " + std::to_string(times) + " times"; \
} \
virtual double lucky_number() { return 7.0; }
B_METHODS
......@@ -178,27 +180,27 @@ class PyA_Repeat : public A_Repeat {
public:
using A_Repeat::A_Repeat;
int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, A_Repeat, say_something, times); }
std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, A_Repeat, say_something, times); }
};
class PyB_Repeat : public B_Repeat {
public:
using B_Repeat::B_Repeat;
int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, B_Repeat, say_something, times); }
std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, B_Repeat, say_something, times); }
double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); }
};
class PyC_Repeat : public C_Repeat {
public:
using C_Repeat::C_Repeat;
int unlucky_number() override { PYBIND11_OVERLOAD(int, C_Repeat, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, C_Repeat, say_something, times); }
std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, C_Repeat, say_something, times); }
double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); }
};
class PyD_Repeat : public D_Repeat {
public:
using D_Repeat::D_Repeat;
int unlucky_number() override { PYBIND11_OVERLOAD(int, D_Repeat, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, D_Repeat, say_something, times); }
std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, D_Repeat, say_something, times); }
double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); }
};
......@@ -221,7 +223,7 @@ class PyA_Tpl : public Base {
public:
using Base::Base; // Inherit constructors
int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, Base, say_something, times); }
std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); }
};
template <class Base = B_Tpl>
class PyB_Tpl : public PyA_Tpl<Base> {
......
import pytest
from pybind11_tests import ConstructorStats
def test_override(capture, msg):
from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual,
runExampleVirtBool)
class ExtendedExampleVirt(ExampleVirt):
def __init__(self, state):
super(ExtendedExampleVirt, self).__init__(state + 1)
self.data = "Hello world"
def run(self, value):
print('ExtendedExampleVirt::run(%i), calling parent..' % value)
return super(ExtendedExampleVirt, self).run(value + 1)
def run_bool(self):
print('ExtendedExampleVirt::run_bool()')
return False
def pure_virtual(self):
print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
ex12 = ExampleVirt(10)
with capture:
assert runExampleVirt(ex12, 20) == 30
assert capture == "Original implementation of ExampleVirt::run(state=10, value=20)"
with pytest.raises(RuntimeError) as excinfo:
runExampleVirtVirtual(ex12)
assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
ex12p = ExtendedExampleVirt(10)
with capture:
assert runExampleVirt(ex12p, 20) == 32
assert capture == """
ExtendedExampleVirt::run(20), calling parent..
Original implementation of ExampleVirt::run(state=11, value=21)
"""
with capture:
assert runExampleVirtBool(ex12p) is False
assert capture == "ExtendedExampleVirt::run_bool()"
with capture:
runExampleVirtVirtual(ex12p)
assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
cstats = ConstructorStats.get(ExampleVirt)
assert cstats.alive() == 2
del ex12, ex12p
assert cstats.alive() == 0
assert cstats.values() == ['10', '11']
assert cstats.copy_constructions == 0
assert cstats.move_constructions >= 0
def test_inheriting_repeat():
from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl
class VI_AR(A_Repeat):
def unlucky_number(self):
return 99
class VI_AT(A_Tpl):
def unlucky_number(self):
return 999
obj = VI_AR()
assert obj.say_something(3) == "hihihi"
assert obj.unlucky_number() == 99
obj = VI_AT()
assert obj.say_something(3) == "hihihi"
assert obj.unlucky_number() == 999
for obj in [B_Repeat(), B_Tpl()]:
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 13
assert obj.lucky_number() == 7.0
for obj in [C_Repeat(), C_Tpl()]:
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 888.0
class VI_CR(C_Repeat):
def lucky_number(self):
return C_Repeat.lucky_number(self) + 1.25
obj = VI_CR()
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 889.25
class VI_CT(C_Tpl):
pass
obj = VI_CT()
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 888.0
class VI_CCR(VI_CR):
def lucky_number(self):
return VI_CR.lucky_number(self) * 10
obj = VI_CCR()
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 8892.5
class VI_CCT(VI_CT):
def lucky_number(self):
return VI_CT.lucky_number(self) * 1000
obj = VI_CCT()
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 888000.0
class VI_DR(D_Repeat):
def unlucky_number(self):
return 123
def lucky_number(self):
return 42.0
for obj in [D_Repeat(), D_Tpl()]:
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 4444
assert obj.lucky_number() == 888.0
obj = VI_DR()
assert obj.say_something(3) == "B says hi 3 times"
assert obj.unlucky_number() == 123
assert obj.lucky_number() == 42.0
class VI_DT(D_Tpl):
def say_something(self, times):
return "VI_DT says:" + (' quack' * times)
def unlucky_number(self):
return 1234
def lucky_number(self):
return -4.25
obj = VI_DT()
assert obj.say_something(3) == "VI_DT says: quack quack quack"
assert obj.unlucky_number() == 1234
assert obj.lucky_number() == -4.25
def test_move_support():
from pybind11_tests import NCVirt, NonCopyable, Movable
class NCVirtExt(NCVirt):
def get_noncopyable(self, a, b):
# Constructs and returns a new instance:
nc = NonCopyable(a*a, b*b)
return nc
def get_movable(self, a, b):
# Return a referenced copy
self.movable = Movable(a, b)
return self.movable
class NCVirtExt2(NCVirt):
def get_noncopyable(self, a, b):
# Keep a reference: this is going to throw an exception
self.nc = NonCopyable(a, b)
return self.nc
def get_movable(self, a, b):
# Return a new instance without storing it
return Movable(a, b)
ncv1 = NCVirtExt()
assert ncv1.print_nc(2, 3) == "36"
assert ncv1.print_movable(4, 5) == "9"
ncv2 = NCVirtExt2()
assert ncv2.print_movable(7, 7) == "14"
# Don't check the exception message here because it differs under debug/non-debug mode
with pytest.raises(RuntimeError):
ncv2.print_nc(9, 9)
nc_stats = ConstructorStats.get(NonCopyable)
mv_stats = ConstructorStats.get(Movable)
assert nc_stats.alive() == 1
assert mv_stats.alive() == 1
del ncv1, ncv2
assert nc_stats.alive() == 0
assert mv_stats.alive() == 0
assert nc_stats.values() == ['4', '9', '9', '9']
assert mv_stats.values() == ['4', '5', '7', '7']
assert nc_stats.copy_constructions == 0
assert mv_stats.copy_constructions == 1
assert nc_stats.move_constructions >= 0
assert mv_stats.move_constructions >= 0
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