test(enum): add test for for #5020: silent conversion to float

Enums (including enum class) are silently converted to floats during
method calls. This can cause overload resolution to fail.

I believe this behavior is a bug. This commit adds tests for that
behavior. These tests fail right now, but they should pass once the
behavior is fixed.

See: https://github.com/pybind/pybind11/issues/5020
This commit is contained in:
Alecto Irene Perez 2024-02-14 13:46:30 -05:00
parent 8b48ff878c
commit 891b0a12b4
2 changed files with 32 additions and 0 deletions

View File

@ -55,6 +55,16 @@ TEST_SUBMODULE(enums, m) {
m.def("test_enum_to_uint", [](uint32_t) {}); m.def("test_enum_to_uint", [](uint32_t) {});
m.def("test_enum_to_long_long", [](long long) {}); m.def("test_enum_to_long_long", [](long long) {});
// Trying to pass an enum to a function that accepts a float should
// trigger a type error
m.def("test_enum_to_float", [](double) {});
// When performing overload resolution, calling f(0, ScopedEnum.TWO)
// should select f(float, ScopedEnum), NOT f(float, float)
m.def("test_enum_overload_resolution", [](double, double) { return "f(float, float)"; });
m.def("test_enum_overload_resolution",
[](double, ScopedEnum) { return "f(float, ScopedEnum)"; });
// test_duplicate_enum_name // test_duplicate_enum_name
enum SimpleEnum { ONE, TWO, THREE }; enum SimpleEnum { ONE, TWO, THREE };

View File

@ -229,6 +229,28 @@ def test_enum_to_int():
m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE) m.test_enum_to_long_long(m.ScopedBoolEnum.TRUE)
def test_enum_overload_resolution():
"""When performing overload resolution, enums should not be silently
converted to floats"""
assert m.test_enum_overload_resolution(0.0, 0.0) == "f(float, float)"
assert m.test_enum_overload_resolution(0, 0) == "f(float, float)"
assert (
m.test_enum_overload_resolution(0.0, m.ScopedEnum.Two) == "f(float, ScopedEnum)"
)
assert (
m.test_enum_overload_resolution(0, m.ScopedEnum.Two) == "f(float, ScopedEnum)"
)
def test_enum_to_float():
"""Passing an enum to a function taking a float should trigger a type error"""
with pytest.raises(TypeError) as execinfo:
m.test_enum_to_float(m.ScopedBoolEnum.TRUE)
assert str(execinfo.value).startswith(
"TypeError: test_enum_to_float(): incompatible function arguments."
)
def test_duplicate_enum_name(): def test_duplicate_enum_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
m.register_bad_enum() m.register_bad_enum()