aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests/test_enum.cpp
blob: 2597b275ef6dc806f33cffb0499fa0ba971a6085 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
    tests/test_enums.cpp -- enumerations

    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>

    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"

TEST_SUBMODULE(enums, m) {
    // test_unscoped_enum
    enum UnscopedEnum { EOne = 1, ETwo, EThree };
    py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration")
        .value("EOne", EOne, "Docstring for EOne")
        .value("ETwo", ETwo, "Docstring for ETwo")
        .value("EThree", EThree, "Docstring for EThree")
        .export_values();

    // test_scoped_enum
    enum class ScopedEnum { Two = 2, Three };
    py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
        .value("Two", ScopedEnum::Two)
        .value("Three", ScopedEnum::Three);

    m.def("test_scoped_enum", [](ScopedEnum z) {
        return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
    });

    // test_binary_operators
    enum Flags { Read = 4, Write = 2, Execute = 1 };
    py::enum_<Flags>(m, "Flags", py::arithmetic())
        .value("Read", Flags::Read)
        .value("Write", Flags::Write)
        .value("Execute", Flags::Execute)
        .export_values();

    // test_implicit_conversion
    class ClassWithUnscopedEnum {
    public:
        enum EMode { EFirstMode = 1, ESecondMode };

        static EMode test_function(EMode mode) { return mode; }
    };
    py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
    exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
    py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
        .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
        .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
        .export_values();

    // test_enum_to_int
    m.def("test_enum_to_int", [](int) {});
    m.def("test_enum_to_uint", [](uint32_t) {});
    m.def("test_enum_to_long_long", [](long long) {});

    // test_duplicate_enum_name
    enum SimpleEnum { ONE, TWO, THREE };

    m.def("register_bad_enum", [m]() {
        py::enum_<SimpleEnum>(m, "SimpleEnum")
            .value("ONE", SimpleEnum::ONE) // NOTE: all value function calls are called with the
                                           // same first parameter value
            .value("ONE", SimpleEnum::TWO)
            .value("ONE", SimpleEnum::THREE)
            .export_values();
    });

    // test_enum_scalar
    enum UnscopedUCharEnum : unsigned char {};
    enum class ScopedShortEnum : short {};
    enum class ScopedLongEnum : long {};
    enum UnscopedUInt64Enum : std::uint64_t {};
    static_assert(
        py::detail::all_of<
            std::is_same<py::enum_<UnscopedUCharEnum>::Scalar, unsigned char>,
            std::is_same<py::enum_<ScopedShortEnum>::Scalar, short>,
            std::is_same<py::enum_<ScopedLongEnum>::Scalar, long>,
            std::is_same<py::enum_<UnscopedUInt64Enum>::Scalar, std::uint64_t>>::value,
        "Error during the deduction of enum's scalar type with normal integer underlying");

    // test_enum_scalar_with_char_underlying
    enum class ScopedCharEnum : char { Zero, Positive };
    enum class ScopedWCharEnum : wchar_t { Zero, Positive };
    enum class ScopedChar32Enum : char32_t { Zero, Positive };
    enum class ScopedChar16Enum : char16_t { Zero, Positive };

    // test the scalar of char type enums according to chapter 'Character types'
    // from https://en.cppreference.com/w/cpp/language/types
    static_assert(
        py::detail::any_of<
            std::is_same<py::enum_<ScopedCharEnum>::Scalar, signed char>,  // e.g. gcc on x86
            std::is_same<py::enum_<ScopedCharEnum>::Scalar, unsigned char> // e.g. arm linux
            >::value,
        "char should be cast to either signed char or unsigned char");
    static_assert(sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 2
                      || sizeof(py::enum_<ScopedWCharEnum>::Scalar) == 4,
                  "wchar_t should be either 16 bits (Windows) or 32 (everywhere else)");
    static_assert(
        py::detail::all_of<
            std::is_same<py::enum_<ScopedChar32Enum>::Scalar, std::uint_least32_t>,
            std::is_same<py::enum_<ScopedChar16Enum>::Scalar, std::uint_least16_t>>::value,
        "char32_t, char16_t (and char8_t)'s size, signedness, and alignment is determined");
#if defined(PYBIND11_HAS_U8STRING)
    enum class ScopedChar8Enum : char8_t { Zero, Positive };
    static_assert(std::is_same<py::enum_<ScopedChar8Enum>::Scalar, unsigned char>::value);
#endif

    // test_char_underlying_enum
    py::enum_<ScopedCharEnum>(m, "ScopedCharEnum")
        .value("Zero", ScopedCharEnum::Zero)
        .value("Positive", ScopedCharEnum::Positive);
    py::enum_<ScopedWCharEnum>(m, "ScopedWCharEnum")
        .value("Zero", ScopedWCharEnum::Zero)
        .value("Positive", ScopedWCharEnum::Positive);
    py::enum_<ScopedChar32Enum>(m, "ScopedChar32Enum")
        .value("Zero", ScopedChar32Enum::Zero)
        .value("Positive", ScopedChar32Enum::Positive);
    py::enum_<ScopedChar16Enum>(m, "ScopedChar16Enum")
        .value("Zero", ScopedChar16Enum::Zero)
        .value("Positive", ScopedChar16Enum::Positive);

    // test_bool_underlying_enum
    enum class ScopedBoolEnum : bool { FALSE, TRUE };

    // bool is unsigned (std::is_signed returns false) and 1-byte long, so represented with u8
    static_assert(std::is_same<py::enum_<ScopedBoolEnum>::Scalar, std::uint8_t>::value, "");

    py::enum_<ScopedBoolEnum>(m, "ScopedBoolEnum")
        .value("FALSE", ScopedBoolEnum::FALSE)
        .value("TRUE", ScopedBoolEnum::TRUE);
}