diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f4339295c..d4db9032a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ set(PYBIND11_TEST_FILES test_buffers.cpp test_callbacks.cpp test_constants_and_functions.cpp + test_enum.cpp test_eval.cpp test_exceptions.cpp test_inheritance.cpp diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp index 507ede828..80ecf0fb0 100644 --- a/tests/pybind11_tests.cpp +++ b/tests/pybind11_tests.cpp @@ -30,6 +30,7 @@ void init_ex_stl_binder_vector(py::module &); void init_ex_eval(py::module &); void init_ex_custom_exceptions(py::module &); void init_ex_numpy_dtypes(py::module &); +void init_ex_enum(py::module &); void init_issues(py::module &); #if defined(PYBIND11_TEST_EIGEN) @@ -74,6 +75,7 @@ PYBIND11_PLUGIN(pybind11_tests) { init_ex_eval(m); init_ex_custom_exceptions(m); init_ex_numpy_dtypes(m); + init_ex_enum(m); init_issues(m); #if defined(PYBIND11_TEST_EIGEN) diff --git a/tests/test_constants_and_functions.cpp b/tests/test_constants_and_functions.cpp index 077fa7884..03f417790 100644 --- a/tests/test_constants_and_functions.cpp +++ b/tests/test_constants_and_functions.cpp @@ -9,33 +9,13 @@ #include "pybind11_tests.h" -enum EMyEnumeration { - EFirstEntry = 1, - ESecondEntry -}; - -enum class ECMyEnum { - Two = 2, - Three -}; - -class ExampleWithEnum { -public: - enum EMode { - EFirstMode = 1, - ESecondMode - }; - - static EMode test_function(EMode mode) { - return mode; - } -}; +enum MyEnum { EFirstEntry = 1, ESecondEntry }; std::string test_function1() { return "test_function()"; } -std::string test_function2(EMyEnumeration k) { +std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; } @@ -43,10 +23,6 @@ std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; } -std::string test_ecenum(ECMyEnum z) { - return "test_ecenum(ECMyEnum::" + std::string(z == ECMyEnum::Two ? "Two" : "Three") + ")"; -} - py::bytes return_bytes() { const char *data = "\x01\x00\x02\x00"; return std::string(data, 4); @@ -63,29 +39,17 @@ std::string print_bytes(py::bytes bytes) { } void init_ex_constants_and_functions(py::module &m) { + m.attr("some_constant") = py::int_(14); + m.def("test_function", &test_function1); m.def("test_function", &test_function2); m.def("test_function", &test_function3); - m.def("test_ecenum", &test_ecenum); - m.attr("some_constant") = py::int_(14); - py::enum_(m, "EMyEnumeration") + py::enum_(m, "MyEnum") .value("EFirstEntry", EFirstEntry) .value("ESecondEntry", ESecondEntry) .export_values(); - py::enum_(m, "ECMyEnum") - .value("Two", ECMyEnum::Two) - .value("Three", ECMyEnum::Three) - ; - - py::class_ exenum_class(m, "ExampleWithEnum"); - exenum_class.def_static("test_function", &ExampleWithEnum::test_function); - py::enum_(exenum_class, "EMode") - .value("EFirstMode", ExampleWithEnum::EFirstMode) - .value("ESecondMode", ExampleWithEnum::ESecondMode) - .export_values(); - m.def("return_bytes", &return_bytes); m.def("print_bytes", &print_bytes); } diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py index 8295ef6f9..2c6321e05 100644 --- a/tests/test_constants_and_functions.py +++ b/tests/test_constants_and_functions.py @@ -1,4 +1,3 @@ -import pytest def test_constants(): @@ -8,74 +7,12 @@ def test_constants(): def test_function_overloading(): - from pybind11_tests import EMyEnumeration, test_function + from pybind11_tests import MyEnum, test_function 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(): - from pybind11_tests import EMyEnumeration, EFirstEntry - - assert str(EMyEnumeration.EFirstEntry) == "EMyEnumeration.EFirstEntry" - assert str(EMyEnumeration.ESecondEntry) == "EMyEnumeration.ESecondEntry" - assert str(EFirstEntry) == "EMyEnumeration.EFirstEntry" - - # no TypeError exception for unscoped enum ==/!= int comparisons - y = EMyEnumeration.ESecondEntry - assert y == 2 - assert y != 3 - - assert int(EMyEnumeration.ESecondEntry) == 2 - assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry" - - -def test_scoped_enum(): - from pybind11_tests import ECMyEnum, test_ecenum - - assert test_ecenum(ECMyEnum.Three) == "test_ecenum(ECMyEnum::Three)" - z = ECMyEnum.Two - assert test_ecenum(z) == "test_ecenum(ECMyEnum::Two)" - - # expected TypeError exceptions for scoped enum ==/!= int comparisons - with pytest.raises(TypeError): - assert z == 2 - with pytest.raises(TypeError): - assert z != 3 - - -def test_implicit_conversion(): - from pybind11_tests import ExampleWithEnum - - assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode" - assert str(ExampleWithEnum.EFirstMode) == "EMode.EFirstMode" - - f = ExampleWithEnum.test_function - first = ExampleWithEnum.EFirstMode - second = ExampleWithEnum.ESecondMode - - assert f(first) == 1 - - assert f(first) == f(first) - assert not f(first) != f(first) - - assert f(first) != f(second) - assert not f(first) == f(second) - - assert f(first) == int(f(first)) - assert not f(first) != int(f(first)) - - assert f(first) != int(f(second)) - assert not f(first) == int(f(second)) - - # noinspection PyDictCreation - x = {f(first): 1, f(second): 2} - x[f(first)] = 3 - x[f(second)] = 4 - # Hashing test - assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" + assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)" + assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)" def test_bytes(): diff --git a/tests/test_enum.cpp b/tests/test_enum.cpp new file mode 100644 index 000000000..e4b2594c5 --- /dev/null +++ b/tests/test_enum.cpp @@ -0,0 +1,57 @@ +/* + tests/test_enums.cpp -- enumerations + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +enum UnscopedEnum { + EOne = 1, + ETwo +}; + +enum class ScopedEnum { + Two = 2, + Three +}; + +class ClassWithUnscopedEnum { +public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + return mode; + } +}; + +std::string test_scoped_enum(ScopedEnum z) { + return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); +} + +void init_ex_enum(py::module &m) { + m.def("test_scoped_enum", &test_scoped_enum); + + py::enum_(m, "UnscopedEnum") + .value("EOne", EOne) + .value("ETwo", ETwo) + .export_values(); + + py::enum_(m, "ScopedEnum") + .value("Two", ScopedEnum::Two) + .value("Three", ScopedEnum::Three) + ; + + py::class_ exenum_class(m, "ClassWithUnscopedEnum"); + exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); + py::enum_(exenum_class, "EMode") + .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode) + .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) + .export_values(); +} diff --git a/tests/test_enum.py b/tests/test_enum.py new file mode 100644 index 000000000..efabae7f7 --- /dev/null +++ b/tests/test_enum.py @@ -0,0 +1,63 @@ +import pytest + + +def test_unscoped_enum(): + from pybind11_tests import UnscopedEnum, EOne + + assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne" + assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" + assert str(EOne) == "UnscopedEnum.EOne" + + # no TypeError exception for unscoped enum ==/!= int comparisons + y = UnscopedEnum.ETwo + assert y == 2 + assert y != 3 + + assert int(UnscopedEnum.ETwo) == 2 + assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo" + + +def test_scoped_enum(): + from pybind11_tests import ScopedEnum, test_scoped_enum + + assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three" + z = ScopedEnum.Two + assert test_scoped_enum(z) == "ScopedEnum::Two" + + # expected TypeError exceptions for scoped enum ==/!= int comparisons + with pytest.raises(TypeError): + assert z == 2 + with pytest.raises(TypeError): + assert z != 3 + + +def test_implicit_conversion(): + from pybind11_tests import ClassWithUnscopedEnum + + assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" + + f = ClassWithUnscopedEnum.test_function + first = ClassWithUnscopedEnum.EFirstMode + second = ClassWithUnscopedEnum.ESecondMode + + assert f(first) == 1 + + assert f(first) == f(first) + assert not f(first) != f(first) + + assert f(first) != f(second) + assert not f(first) == f(second) + + assert f(first) == int(f(first)) + assert not f(first) != int(f(first)) + + assert f(first) != int(f(second)) + assert not f(first) == int(f(second)) + + # noinspection PyDictCreation + x = {f(first): 1, f(second): 2} + x[f(first)] = 3 + x[f(second)] = 4 + # Hashing test + assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"