1# -*- coding: utf-8 -*- 2import pytest 3from pybind11_tests import enums as m 4 5 6def test_unscoped_enum(): 7 assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" 8 assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" 9 assert str(m.EOne) == "UnscopedEnum.EOne" 10 assert repr(m.UnscopedEnum.EOne) == "<UnscopedEnum.EOne: 1>" 11 assert repr(m.UnscopedEnum.ETwo) == "<UnscopedEnum.ETwo: 2>" 12 assert repr(m.EOne) == "<UnscopedEnum.EOne: 1>" 13 14 # name property 15 assert m.UnscopedEnum.EOne.name == "EOne" 16 assert m.UnscopedEnum.EOne.value == 1 17 assert m.UnscopedEnum.ETwo.name == "ETwo" 18 assert m.UnscopedEnum.ETwo.value == 2 19 assert m.EOne is m.UnscopedEnum.EOne 20 # name, value readonly 21 with pytest.raises(AttributeError): 22 m.UnscopedEnum.EOne.name = "" 23 with pytest.raises(AttributeError): 24 m.UnscopedEnum.EOne.value = 10 25 # name, value returns a copy 26 # TODO: Neither the name nor value tests actually check against aliasing. 27 # Use a mutable type that has reference semantics. 28 nonaliased_name = m.UnscopedEnum.EOne.name 29 nonaliased_name = "bar" # noqa: F841 30 assert m.UnscopedEnum.EOne.name == "EOne" 31 nonaliased_value = m.UnscopedEnum.EOne.value 32 nonaliased_value = 10 # noqa: F841 33 assert m.UnscopedEnum.EOne.value == 1 34 35 # __members__ property 36 assert m.UnscopedEnum.__members__ == { 37 "EOne": m.UnscopedEnum.EOne, 38 "ETwo": m.UnscopedEnum.ETwo, 39 "EThree": m.UnscopedEnum.EThree, 40 } 41 # __members__ readonly 42 with pytest.raises(AttributeError): 43 m.UnscopedEnum.__members__ = {} 44 # __members__ returns a copy 45 nonaliased_members = m.UnscopedEnum.__members__ 46 nonaliased_members["bar"] = "baz" 47 assert m.UnscopedEnum.__members__ == { 48 "EOne": m.UnscopedEnum.EOne, 49 "ETwo": m.UnscopedEnum.ETwo, 50 "EThree": m.UnscopedEnum.EThree, 51 } 52 53 for docstring_line in """An unscoped enumeration 54 55Members: 56 57 EOne : Docstring for EOne 58 59 ETwo : Docstring for ETwo 60 61 EThree : Docstring for EThree""".split( 62 "\n" 63 ): 64 assert docstring_line in m.UnscopedEnum.__doc__ 65 66 # Unscoped enums will accept ==/!= int comparisons 67 y = m.UnscopedEnum.ETwo 68 assert y == 2 69 assert 2 == y 70 assert y != 3 71 assert 3 != y 72 # Compare with None 73 assert y != None # noqa: E711 74 assert not (y == None) # noqa: E711 75 # Compare with an object 76 assert y != object() 77 assert not (y == object()) 78 # Compare with string 79 assert y != "2" 80 assert "2" != y 81 assert not ("2" == y) 82 assert not (y == "2") 83 84 with pytest.raises(TypeError): 85 y < object() # noqa: B015 86 87 with pytest.raises(TypeError): 88 y <= object() # noqa: B015 89 90 with pytest.raises(TypeError): 91 y > object() # noqa: B015 92 93 with pytest.raises(TypeError): 94 y >= object() # noqa: B015 95 96 with pytest.raises(TypeError): 97 y | object() # noqa: B015 98 99 with pytest.raises(TypeError): 100 y & object() # noqa: B015 101 102 with pytest.raises(TypeError): 103 y ^ object() # noqa: B015 104 105 assert int(m.UnscopedEnum.ETwo) == 2 106 assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" 107 108 # order 109 assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo 110 assert m.UnscopedEnum.EOne < 2 111 assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne 112 assert m.UnscopedEnum.ETwo > 1 113 assert m.UnscopedEnum.ETwo <= 2 114 assert m.UnscopedEnum.ETwo >= 2 115 assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo 116 assert m.UnscopedEnum.EOne <= 2 117 assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne 118 assert m.UnscopedEnum.ETwo >= 1 119 assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne) 120 assert not (2 < m.UnscopedEnum.EOne) 121 122 # arithmetic 123 assert m.UnscopedEnum.EOne & m.UnscopedEnum.EThree == m.UnscopedEnum.EOne 124 assert m.UnscopedEnum.EOne | m.UnscopedEnum.ETwo == m.UnscopedEnum.EThree 125 assert m.UnscopedEnum.EOne ^ m.UnscopedEnum.EThree == m.UnscopedEnum.ETwo 126 127 128def test_scoped_enum(): 129 assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three" 130 z = m.ScopedEnum.Two 131 assert m.test_scoped_enum(z) == "ScopedEnum::Two" 132 133 # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False) 134 assert not z == 3 135 assert not 3 == z 136 assert z != 3 137 assert 3 != z 138 # Compare with None 139 assert z != None # noqa: E711 140 assert not (z == None) # noqa: E711 141 # Compare with an object 142 assert z != object() 143 assert not (z == object()) 144 # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) 145 with pytest.raises(TypeError): 146 z > 3 # noqa: B015 147 with pytest.raises(TypeError): 148 z < 3 # noqa: B015 149 with pytest.raises(TypeError): 150 z >= 3 # noqa: B015 151 with pytest.raises(TypeError): 152 z <= 3 # noqa: B015 153 154 # order 155 assert m.ScopedEnum.Two < m.ScopedEnum.Three 156 assert m.ScopedEnum.Three > m.ScopedEnum.Two 157 assert m.ScopedEnum.Two <= m.ScopedEnum.Three 158 assert m.ScopedEnum.Two <= m.ScopedEnum.Two 159 assert m.ScopedEnum.Two >= m.ScopedEnum.Two 160 assert m.ScopedEnum.Three >= m.ScopedEnum.Two 161 162 163def test_implicit_conversion(): 164 assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" 165 assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" 166 assert repr(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "<EMode.EFirstMode: 1>" 167 assert repr(m.ClassWithUnscopedEnum.EFirstMode) == "<EMode.EFirstMode: 1>" 168 169 f = m.ClassWithUnscopedEnum.test_function 170 first = m.ClassWithUnscopedEnum.EFirstMode 171 second = m.ClassWithUnscopedEnum.ESecondMode 172 173 assert f(first) == 1 174 175 assert f(first) == f(first) 176 assert not f(first) != f(first) 177 178 assert f(first) != f(second) 179 assert not f(first) == f(second) 180 181 assert f(first) == int(f(first)) 182 assert not f(first) != int(f(first)) 183 184 assert f(first) != int(f(second)) 185 assert not f(first) == int(f(second)) 186 187 # noinspection PyDictCreation 188 x = {f(first): 1, f(second): 2} 189 x[f(first)] = 3 190 x[f(second)] = 4 191 # Hashing test 192 assert repr(x) == "{<EMode.EFirstMode: 1>: 3, <EMode.ESecondMode: 2>: 4}" 193 194 195def test_binary_operators(): 196 assert int(m.Flags.Read) == 4 197 assert int(m.Flags.Write) == 2 198 assert int(m.Flags.Execute) == 1 199 assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7 200 assert int(m.Flags.Read | m.Flags.Write) == 6 201 assert int(m.Flags.Read | m.Flags.Execute) == 5 202 assert int(m.Flags.Write | m.Flags.Execute) == 3 203 assert int(m.Flags.Write | 1) == 3 204 assert ~m.Flags.Write == -3 205 206 state = m.Flags.Read | m.Flags.Write 207 assert (state & m.Flags.Read) != 0 208 assert (state & m.Flags.Write) != 0 209 assert (state & m.Flags.Execute) == 0 210 assert (state & 1) == 0 211 212 state2 = ~state 213 assert state2 == -7 214 assert int(state ^ state2) == -1 215 216 217def test_enum_to_int(): 218 m.test_enum_to_int(m.Flags.Read) 219 m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) 220 m.test_enum_to_uint(m.Flags.Read) 221 m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) 222 m.test_enum_to_long_long(m.Flags.Read) 223 m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) 224 225 226def test_duplicate_enum_name(): 227 with pytest.raises(ValueError) as excinfo: 228 m.register_bad_enum() 229 assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!' 230 231 232def test_docstring_signatures(): 233 for enum_type in [m.ScopedEnum, m.UnscopedEnum]: 234 for attr in enum_type.__dict__.values(): 235 # Issue #2623/PR #2637: Add argument names to enum_ methods 236 assert "arg0" not in (attr.__doc__ or "") 237