You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
5.3 KiB

  1. import pytest
  2. from pybind11_tests import ExampleMandA, ConstructorStats
  3. def test_methods_and_attributes():
  4. instance1 = ExampleMandA()
  5. instance2 = ExampleMandA(32)
  6. instance1.add1(instance2)
  7. instance1.add2(instance2)
  8. instance1.add3(instance2)
  9. instance1.add4(instance2)
  10. instance1.add5(instance2)
  11. instance1.add6(32)
  12. instance1.add7(32)
  13. instance1.add8(32)
  14. instance1.add9(32)
  15. instance1.add10(32)
  16. assert str(instance1) == "ExampleMandA[value=320]"
  17. assert str(instance2) == "ExampleMandA[value=32]"
  18. assert str(instance1.self1()) == "ExampleMandA[value=320]"
  19. assert str(instance1.self2()) == "ExampleMandA[value=320]"
  20. assert str(instance1.self3()) == "ExampleMandA[value=320]"
  21. assert str(instance1.self4()) == "ExampleMandA[value=320]"
  22. assert str(instance1.self5()) == "ExampleMandA[value=320]"
  23. assert instance1.internal1() == 320
  24. assert instance1.internal2() == 320
  25. assert instance1.internal3() == 320
  26. assert instance1.internal4() == 320
  27. assert instance1.internal5() == 320
  28. assert instance1.value == 320
  29. instance1.value = 100
  30. assert str(instance1) == "ExampleMandA[value=100]"
  31. cstats = ConstructorStats.get(ExampleMandA)
  32. assert cstats.alive() == 2
  33. del instance1, instance2
  34. assert cstats.alive() == 0
  35. assert cstats.values() == ["32"]
  36. assert cstats.default_constructions == 1
  37. assert cstats.copy_constructions == 3
  38. assert cstats.move_constructions >= 1
  39. assert cstats.copy_assignments == 0
  40. assert cstats.move_assignments == 0
  41. def test_properties():
  42. from pybind11_tests import TestProperties
  43. instance = TestProperties()
  44. assert instance.def_readonly == 1
  45. with pytest.raises(AttributeError):
  46. instance.def_readonly = 2
  47. instance.def_readwrite = 2
  48. assert instance.def_readwrite == 2
  49. assert instance.def_property_readonly == 2
  50. with pytest.raises(AttributeError):
  51. instance.def_property_readonly = 3
  52. instance.def_property = 3
  53. assert instance.def_property == 3
  54. def test_static_properties():
  55. from pybind11_tests import TestProperties as Type
  56. assert Type.def_readonly_static == 1
  57. with pytest.raises(AttributeError):
  58. Type.def_readonly_static = 2
  59. Type.def_readwrite_static = 2
  60. assert Type.def_readwrite_static == 2
  61. assert Type.def_property_readonly_static == 2
  62. with pytest.raises(AttributeError):
  63. Type.def_property_readonly_static = 3
  64. Type.def_property_static = 3
  65. assert Type.def_property_static == 3
  66. @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
  67. def test_property_return_value_policies(access):
  68. from pybind11_tests import TestPropRVP
  69. if not access.startswith("static"):
  70. obj = TestPropRVP()
  71. else:
  72. obj = TestPropRVP
  73. ref = getattr(obj, access + "_ref")
  74. assert ref.value == 1
  75. ref.value = 2
  76. assert getattr(obj, access + "_ref").value == 2
  77. ref.value = 1 # restore original value for static properties
  78. copy = getattr(obj, access + "_copy")
  79. assert copy.value == 1
  80. copy.value = 2
  81. assert getattr(obj, access + "_copy").value == 1
  82. copy = getattr(obj, access + "_func")
  83. assert copy.value == 1
  84. copy.value = 2
  85. assert getattr(obj, access + "_func").value == 1
  86. def test_property_rvalue_policy():
  87. """When returning an rvalue, the return value policy is automatically changed from
  88. `reference(_internal)` to `move`. The following would not work otherwise.
  89. """
  90. from pybind11_tests import TestPropRVP
  91. instance = TestPropRVP()
  92. o = instance.rvalue
  93. assert o.value == 1
  94. o = TestPropRVP.static_rvalue
  95. assert o.value == 1
  96. def test_dynamic_attributes():
  97. from pybind11_tests import DynamicClass, CppDerivedDynamicClass
  98. instance = DynamicClass()
  99. assert not hasattr(instance, "foo")
  100. assert "foo" not in dir(instance)
  101. # Dynamically add attribute
  102. instance.foo = 42
  103. assert hasattr(instance, "foo")
  104. assert instance.foo == 42
  105. assert "foo" in dir(instance)
  106. # __dict__ should be accessible and replaceable
  107. assert "foo" in instance.__dict__
  108. instance.__dict__ = {"bar": True}
  109. assert not hasattr(instance, "foo")
  110. assert hasattr(instance, "bar")
  111. with pytest.raises(TypeError) as excinfo:
  112. instance.__dict__ = []
  113. assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
  114. cstats = ConstructorStats.get(DynamicClass)
  115. assert cstats.alive() == 1
  116. del instance
  117. assert cstats.alive() == 0
  118. # Derived classes should work as well
  119. class PythonDerivedDynamicClass(DynamicClass):
  120. pass
  121. for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass:
  122. derived = cls()
  123. derived.foobar = 100
  124. assert derived.foobar == 100
  125. assert cstats.alive() == 1
  126. del derived
  127. assert cstats.alive() == 0
  128. def test_cyclic_gc():
  129. from pybind11_tests import DynamicClass
  130. # One object references itself
  131. instance = DynamicClass()
  132. instance.circular_reference = instance
  133. cstats = ConstructorStats.get(DynamicClass)
  134. assert cstats.alive() == 1
  135. del instance
  136. assert cstats.alive() == 0
  137. # Two object reference each other
  138. i1 = DynamicClass()
  139. i2 = DynamicClass()
  140. i1.cycle = i2
  141. i2.cycle = i1
  142. assert cstats.alive() == 2
  143. del i1, i2
  144. assert cstats.alive() == 0