diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 9d62420f240338d5926f7f3963234643e514393f..7b171d71b4c33d0f24cbc239039f548a8613759e 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -39,7 +39,24 @@ if(NOT NUMPY_WITH_BROKEN_UFUNC_SUPPORT) endif() add_lib_unit_test(std_vector) add_lib_unit_test(user_struct) -add_lib_unit_test(bind_optional) + +function(config_bind_optional tagname opttype) + set(MODNAME bind_optional_${tagname}) + set(OPTIONAL ${opttype}) + configure_file(bind_optional.cpp.in ${MODNAME}.cpp) + + set(py_file test_optional_${tagname}.py) + configure_file(python/test_optional.py.in ${CMAKE_CURRENT_SOURCE_DIR}/python/${py_file}) + add_lib_unit_test(${MODNAME}) + message(STATUS "Adding unit test py-optional-${tagname} with file ${py_file} and module ${MODNAME}") + add_python_unit_test("py-optional-${tagname}" "unittest/python/${py_file}" + "unittest") +endfunction() + +config_bind_optional(boost "boost::optional") +if(CMAKE_CXX_STANDARD GREATER 14 AND CMAKE_CXX_STANDARD LESS 98) + config_bind_optional(std "std::optional") +endif() add_python_unit_test("py-matrix" "unittest/python/test_matrix.py" "unittest") @@ -98,6 +115,3 @@ set_tests_properties("py-std-vector" PROPERTIES DEPENDS ${PYWRAP}) add_python_unit_test("py-user-struct" "unittest/python/test_user_struct.py" "python;unittest") set_tests_properties("py-std-vector" PROPERTIES DEPENDS ${PYWRAP}) - -add_python_unit_test("py-optional" "unittest/python/test_optional.py" - "unittest") diff --git a/unittest/bind_optional.cpp b/unittest/bind_optional.cpp.in similarity index 73% rename from unittest/bind_optional.cpp rename to unittest/bind_optional.cpp.in index 6d85795c4306e2f435250f6deffcceb14aba9f33..f6827872af0d9433c634d0d2c31c344b1ee38d8f 100644 --- a/unittest/bind_optional.cpp +++ b/unittest/bind_optional.cpp.in @@ -1,16 +1,20 @@ #include "eigenpy/eigenpy.hpp" #include "eigenpy/optional.hpp" +#ifdef EIGENPY_WITH_CXX17_SUPPORT +#include <optional> +#endif -#define OPTIONAL boost::optional -#define OPT_NONE boost::none +#cmakedefine OPTIONAL @OPTIONAL@ -using opt_dbl = OPTIONAL<double>; +typedef eigenpy::detail::nullopt_helper<OPTIONAL> none_helper; +static auto OPT_NONE = none_helper::value(); +typedef OPTIONAL<double> opt_dbl; struct mystruct { OPTIONAL<int> a; opt_dbl b; OPTIONAL<std::string> msg{"i am struct"}; - mystruct() : a(OPT_NONE), b(boost::none) {} + mystruct() : a(OPT_NONE), b(OPT_NONE) {} mystruct(int a, const opt_dbl &b = OPT_NONE) : a(a), b(b) {} }; @@ -36,13 +40,13 @@ OPTIONAL<Eigen::MatrixXd> random_mat_if_true(bool flag) { return OPT_NONE; } -BOOST_PYTHON_MODULE(bind_optional) { +BOOST_PYTHON_MODULE(@MODNAME@) { using namespace eigenpy; - OptionalConverter<int>::registration(); - OptionalConverter<double>::registration(); - OptionalConverter<std::string>::registration(); - OptionalConverter<mystruct>::registration(); - OptionalConverter<Eigen::MatrixXd>::registration(); + OptionalConverter<int, OPTIONAL>::registration(); + OptionalConverter<double, OPTIONAL>::registration(); + OptionalConverter<std::string, OPTIONAL>::registration(); + OptionalConverter<mystruct, OPTIONAL>::registration(); + OptionalConverter<Eigen::MatrixXd, OPTIONAL>::registration(); enableEigenPy(); bp::class_<mystruct>("mystruct", bp::no_init) diff --git a/unittest/python/test_optional.py b/unittest/python/test_optional.py.in similarity index 88% rename from unittest/python/test_optional.py rename to unittest/python/test_optional.py.in index d6a29738c2b4c77edfadba79b22d3a6c334fc8e3..bd5e085ec076bf2a5ce3ed8645f3b3624b95b494 100644 --- a/unittest/python/test_optional.py +++ b/unittest/python/test_optional.py.in @@ -1,4 +1,6 @@ -import bind_optional +import importlib + +bind_optional = importlib.import_module("@MODNAME@") def test_none_if_zero(): @@ -58,8 +60,8 @@ def test_random_mat(): assert M.shape == (4, 4) -if __name__ == "__main__": - import pytest - import sys - - sys.exit(pytest.main(sys.argv)) +test_none_if_zero() +test_struct_ctors() +test_struct_setters() +test_factory() +test_random_mat() diff --git a/unittest/python/test_optional_boost.py b/unittest/python/test_optional_boost.py new file mode 100644 index 0000000000000000000000000000000000000000..fc818739d90e89be9d41f8f26c0f1f560ef5f4b7 --- /dev/null +++ b/unittest/python/test_optional_boost.py @@ -0,0 +1,67 @@ +import importlib + +bind_optional = importlib.import_module("bind_optional_boost") + + +def test_none_if_zero(): + x = bind_optional.none_if_zero(0) + y = bind_optional.none_if_zero(-1) + assert x is None + assert y == -1 + + +def test_struct_ctors(): + # test struct ctors + + struct = bind_optional.mystruct() + assert struct.a is None + assert struct.b is None + assert struct.msg == "i am struct" + + ## no 2nd arg automatic overload using bp::optional + struct = bind_optional.mystruct(2) + assert struct.a == 2 + assert struct.b is None + + struct = bind_optional.mystruct(13, -1.0) + assert struct.a == 13 + assert struct.b == -1.0 + + +def test_struct_setters(): + struct = bind_optional.mystruct() + struct.a = 1 + assert struct.a == 1 + + struct.b = -3.14 + assert struct.b == -3.14 + + # set to None + struct.a = None + struct.b = None + struct.msg = None + assert struct.a is None + assert struct.b is None + assert struct.msg is None + + +def test_factory(): + struct = bind_optional.create_if_true(False, None) + assert struct is None + struct = bind_optional.create_if_true(True, None) + assert struct.a == 0 + assert struct.b is None + + +def test_random_mat(): + M = bind_optional.random_mat_if_true(False) + assert M is None + M = bind_optional.random_mat_if_true(True) + assert M.shape == (4, 4) + + +test_none_if_zero() +test_struct_ctors() +test_struct_setters() +test_factory() +test_random_mat() diff --git a/unittest/python/test_optional_std.py b/unittest/python/test_optional_std.py new file mode 100644 index 0000000000000000000000000000000000000000..69949a44f46b3f2ea010af24a3478d0a67fb8e5f --- /dev/null +++ b/unittest/python/test_optional_std.py @@ -0,0 +1,67 @@ +import importlib + +bind_optional = importlib.import_module("bind_optional_std") + + +def test_none_if_zero(): + x = bind_optional.none_if_zero(0) + y = bind_optional.none_if_zero(-1) + assert x is None + assert y == -1 + + +def test_struct_ctors(): + # test struct ctors + + struct = bind_optional.mystruct() + assert struct.a is None + assert struct.b is None + assert struct.msg == "i am struct" + + ## no 2nd arg automatic overload using bp::optional + struct = bind_optional.mystruct(2) + assert struct.a == 2 + assert struct.b is None + + struct = bind_optional.mystruct(13, -1.0) + assert struct.a == 13 + assert struct.b == -1.0 + + +def test_struct_setters(): + struct = bind_optional.mystruct() + struct.a = 1 + assert struct.a == 1 + + struct.b = -3.14 + assert struct.b == -3.14 + + # set to None + struct.a = None + struct.b = None + struct.msg = None + assert struct.a is None + assert struct.b is None + assert struct.msg is None + + +def test_factory(): + struct = bind_optional.create_if_true(False, None) + assert struct is None + struct = bind_optional.create_if_true(True, None) + assert struct.a == 0 + assert struct.b is None + + +def test_random_mat(): + M = bind_optional.random_mat_if_true(False) + assert M is None + M = bind_optional.random_mat_if_true(True) + assert M.shape == (4, 4) + + +test_none_if_zero() +test_struct_ctors() +test_struct_setters() +test_factory() +test_random_mat()