aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests/test_enum.py
blob: f6b24fc2336580ea218c6cdde48c835c57b7640f (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# -*- coding: utf-8 -*-
import pytest
from pybind11_tests import enums as m


def test_unscoped_enum():
    assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
    assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
    assert str(m.EOne) == "UnscopedEnum.EOne"
    assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>"
    assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>"
    assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>"

    # name property
    assert m.UnscopedEnum.EOne.name == "EOne"
    assert m.UnscopedEnum.ETwo.name == "ETwo"
    assert m.EOne.name == "EOne"
    # name readonly
    with pytest.raises(AttributeError):
        m.UnscopedEnum.EOne.name = ""
    # name returns a copy
    foo = m.UnscopedEnum.EOne.name
    foo = "bar"
    assert m.UnscopedEnum.EOne.name == "EOne"

    # __members__ property
    assert m.UnscopedEnum.__members__ == {
        "EOne": m.UnscopedEnum.EOne,
        "ETwo": m.UnscopedEnum.ETwo,
        "EThree": m.UnscopedEnum.EThree,
    }
    # __members__ readonly
    with pytest.raises(AttributeError):
        m.UnscopedEnum.__members__ = {}
    # __members__ returns a copy
    foo = m.UnscopedEnum.__members__
    foo["bar"] = "baz"
    assert m.UnscopedEnum.__members__ == {
        "EOne": m.UnscopedEnum.EOne,
        "ETwo": m.UnscopedEnum.ETwo,
        "EThree": m.UnscopedEnum.EThree,
    }

    for docstring_line in """An unscoped enumeration

Members:

  EOne : Docstring for EOne

  ETwo : Docstring for ETwo

  EThree : Docstring for EThree""".split(
        "\n"
    ):
        assert docstring_line in m.UnscopedEnum.__doc__

    # Unscoped enums will accept ==/!= int comparisons
    y = m.UnscopedEnum.ETwo
    assert y == 2
    assert 2 == y
    assert y != 3
    assert 3 != y
    # Compare with None
    assert y != None  # noqa: E711
    assert not (y == None)  # noqa: E711
    # Compare with an object
    assert y != object()
    assert not (y == object())
    # Compare with string
    assert y != "2"
    assert "2" != y
    assert not ("2" == y)
    assert not (y == "2")

    with pytest.raises(TypeError):
        y < object()

    with pytest.raises(TypeError):
        y <= object()

    with pytest.raises(TypeError):
        y > object()

    with pytest.raises(TypeError):
        y >= object()

    with pytest.raises(TypeError):
        y | object()

    with pytest.raises(TypeError):
        y & object()

    with pytest.raises(TypeError):
        y ^ object()

    assert int(m.UnscopedEnum.ETwo) == 2
    assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"

    # order
    assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
    assert m.UnscopedEnum.EOne < 2
    assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
    assert m.UnscopedEnum.ETwo > 1
    assert m.UnscopedEnum.ETwo <= 2
    assert m.UnscopedEnum.ETwo >= 2
    assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
    assert m.UnscopedEnum.EOne <= 2
    assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
    assert m.UnscopedEnum.ETwo >= 1
    assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
    assert not (2 < m.UnscopedEnum.EOne)

    # arithmetic
    assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne
    assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree
    assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo


def test_scoped_enum():
    assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
    z = m.ScopedEnum.Two
    assert m.test_scoped_enum(z) == "ScopedEnum::Two"

    # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False)
    assert not z == 3
    assert not 3 == z
    assert z != 3
    assert 3 != z
    # Compare with None
    assert z != None  # noqa: E711
    assert not (z == None)  # noqa: E711
    # Compare with an object
    assert z != object()
    assert not (z == object())
    # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions)
    with pytest.raises(TypeError):
        z > 3
    with pytest.raises(TypeError):
        z < 3
    with pytest.raises(TypeError):
        z >= 3
    with pytest.raises(TypeError):
        z <= 3

    # order
    assert m.ScopedEnum.Two < m.ScopedEnum.Three
    assert m.ScopedEnum.Three > m.ScopedEnum.Two
    assert m.ScopedEnum.Two <= m.ScopedEnum.Three
    assert m.ScopedEnum.Two <= m.ScopedEnum.Two
    assert m.ScopedEnum.Two >= m.ScopedEnum.Two
    assert m.ScopedEnum.Three >= m.ScopedEnum.Two


def test_implicit_conversion():
    assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
    assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
    assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>"
    assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>"

    f = m.ClassWithUnscopedEnum.test_function
    first = m.ClassWithUnscopedEnum.EFirstMode
    second = m.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 repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}"


def test_binary_operators():
    assert int(m.Flags.Read) == 4
    assert int(m.Flags.Write) == 2
    assert int(m.Flags.Execute) == 1
    assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
    assert int(m.Flags.Read | m.Flags.Write) == 6
    assert int(m.Flags.Read | m.Flags.Execute) == 5
    assert int(m.Flags.Write | m.Flags.Execute) == 3
    assert int(m.Flags.Write | 1) == 3
    assert ~m.Flags.Write == -3

    state = m.Flags.Read | m.Flags.Write
    assert (state & m.Flags.Read) != 0
    assert (state & m.Flags.Write) != 0
    assert (state & m.Flags.Execute) == 0
    assert (state & 1) == 0

    state2 = ~state
    assert state2 == -7
    assert int(state ^ state2) == -1


def test_enum_to_int():
    m.test_enum_to_int(m.Flags.Read)
    m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
    m.test_enum_to_uint(m.Flags.Read)
    m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
    m.test_enum_to_long_long(m.Flags.Read)
    m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)


def test_duplicate_enum_name():
    with pytest.raises(ValueError) as excinfo:
        m.register_bad_enum()
    assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!'


def test_docstring_signatures():
    for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
        for attr in enum_type.__dict__.values():
            # Issue #2623/PR #2637: Add argument names to enum_ methods
            assert "arg0" not in (attr.__doc__ or "")