test_enum.py 7.5 KB

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