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.

248 lines
8.5 KiB

2 months ago
  1. import pytest
  2. from pybind11_tests import ConstructorStats
  3. def test_smart_ptr(capture):
  4. # Object1
  5. from pybind11_tests import (MyObject1, make_object_1, make_object_2,
  6. print_object_1, print_object_2, print_object_3, print_object_4)
  7. for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1):
  8. assert o.getRefCount() == 1
  9. with capture:
  10. print_object_1(o)
  11. print_object_2(o)
  12. print_object_3(o)
  13. print_object_4(o)
  14. assert capture == "MyObject1[{i}]\n".format(i=i) * 4
  15. from pybind11_tests import (make_myobject1_1, make_myobject1_2,
  16. print_myobject1_1, print_myobject1_2,
  17. print_myobject1_3, print_myobject1_4)
  18. for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4):
  19. print(o)
  20. with capture:
  21. if not isinstance(o, int):
  22. print_object_1(o)
  23. print_object_2(o)
  24. print_object_3(o)
  25. print_object_4(o)
  26. print_myobject1_1(o)
  27. print_myobject1_2(o)
  28. print_myobject1_3(o)
  29. print_myobject1_4(o)
  30. assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
  31. cstats = ConstructorStats.get(MyObject1)
  32. assert cstats.alive() == 0
  33. expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
  34. assert cstats.values() == expected_values
  35. assert cstats.default_constructions == 0
  36. assert cstats.copy_constructions == 0
  37. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  38. assert cstats.copy_assignments == 0
  39. assert cstats.move_assignments == 0
  40. # Object2
  41. from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2,
  42. make_myobject3_1, make_myobject3_2,
  43. print_myobject2_1, print_myobject2_2,
  44. print_myobject2_3, print_myobject2_4)
  45. for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]):
  46. print(o)
  47. with capture:
  48. print_myobject2_1(o)
  49. print_myobject2_2(o)
  50. print_myobject2_3(o)
  51. print_myobject2_4(o)
  52. assert capture == "MyObject2[{i}]\n".format(i=i) * 4
  53. cstats = ConstructorStats.get(MyObject2)
  54. assert cstats.alive() == 1
  55. o = None
  56. assert cstats.alive() == 0
  57. assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
  58. assert cstats.default_constructions == 0
  59. assert cstats.copy_constructions == 0
  60. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  61. assert cstats.copy_assignments == 0
  62. assert cstats.move_assignments == 0
  63. # Object3
  64. from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2,
  65. print_myobject3_3, print_myobject3_4)
  66. for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]):
  67. print(o)
  68. with capture:
  69. print_myobject3_1(o)
  70. print_myobject3_2(o)
  71. print_myobject3_3(o)
  72. print_myobject3_4(o)
  73. assert capture == "MyObject3[{i}]\n".format(i=i) * 4
  74. cstats = ConstructorStats.get(MyObject3)
  75. assert cstats.alive() == 1
  76. o = None
  77. assert cstats.alive() == 0
  78. assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
  79. assert cstats.default_constructions == 0
  80. assert cstats.copy_constructions == 0
  81. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  82. assert cstats.copy_assignments == 0
  83. assert cstats.move_assignments == 0
  84. # Object and ref
  85. from pybind11_tests import Object, cstats_ref
  86. cstats = ConstructorStats.get(Object)
  87. assert cstats.alive() == 0
  88. assert cstats.values() == []
  89. assert cstats.default_constructions == 10
  90. assert cstats.copy_constructions == 0
  91. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  92. assert cstats.copy_assignments == 0
  93. assert cstats.move_assignments == 0
  94. cstats = cstats_ref()
  95. assert cstats.alive() == 0
  96. assert cstats.values() == ['from pointer'] * 10
  97. assert cstats.default_constructions == 30
  98. assert cstats.copy_constructions == 12
  99. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  100. assert cstats.copy_assignments == 30
  101. assert cstats.move_assignments == 0
  102. def test_smart_ptr_refcounting():
  103. from pybind11_tests import test_object1_refcounting
  104. assert test_object1_refcounting()
  105. def test_unique_nodelete():
  106. from pybind11_tests import MyObject4
  107. o = MyObject4(23)
  108. assert o.value == 23
  109. cstats = ConstructorStats.get(MyObject4)
  110. assert cstats.alive() == 1
  111. del o
  112. cstats = ConstructorStats.get(MyObject4)
  113. assert cstats.alive() == 1 # Leak, but that's intentional
  114. def test_large_holder():
  115. from pybind11_tests import MyObject5
  116. o = MyObject5(5)
  117. assert o.value == 5
  118. cstats = ConstructorStats.get(MyObject5)
  119. assert cstats.alive() == 1
  120. del o
  121. assert cstats.alive() == 0
  122. def test_shared_ptr_and_references():
  123. from pybind11_tests.smart_ptr import SharedPtrRef, A
  124. s = SharedPtrRef()
  125. stats = ConstructorStats.get(A)
  126. assert stats.alive() == 2
  127. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
  128. assert stats.alive() == 2
  129. assert s.set_ref(ref)
  130. with pytest.raises(RuntimeError) as excinfo:
  131. assert s.set_holder(ref)
  132. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  133. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
  134. assert stats.alive() == 3
  135. assert s.set_ref(copy)
  136. assert s.set_holder(copy)
  137. holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
  138. assert stats.alive() == 3
  139. assert s.set_ref(holder_ref)
  140. assert s.set_holder(holder_ref)
  141. holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
  142. assert stats.alive() == 3
  143. assert s.set_ref(holder_copy)
  144. assert s.set_holder(holder_copy)
  145. del ref, copy, holder_ref, holder_copy, s
  146. assert stats.alive() == 0
  147. def test_shared_ptr_from_this_and_references():
  148. from pybind11_tests.smart_ptr import SharedFromThisRef, B, SharedFromThisVirt
  149. s = SharedFromThisRef()
  150. stats = ConstructorStats.get(B)
  151. assert stats.alive() == 2
  152. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
  153. assert stats.alive() == 2
  154. assert s.set_ref(ref)
  155. assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
  156. bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
  157. assert stats.alive() == 2
  158. assert s.set_ref(bad_wp)
  159. with pytest.raises(RuntimeError) as excinfo:
  160. assert s.set_holder(bad_wp)
  161. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  162. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
  163. assert stats.alive() == 3
  164. assert s.set_ref(copy)
  165. assert s.set_holder(copy)
  166. holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
  167. assert stats.alive() == 3
  168. assert s.set_ref(holder_ref)
  169. assert s.set_holder(holder_ref)
  170. holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
  171. assert stats.alive() == 3
  172. assert s.set_ref(holder_copy)
  173. assert s.set_holder(holder_copy)
  174. del ref, bad_wp, copy, holder_ref, holder_copy, s
  175. assert stats.alive() == 0
  176. z = SharedFromThisVirt.get()
  177. y = SharedFromThisVirt.get()
  178. assert y is z
  179. def test_move_only_holder():
  180. from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder
  181. a = TypeWithMoveOnlyHolder.make()
  182. stats = ConstructorStats.get(TypeWithMoveOnlyHolder)
  183. assert stats.alive() == 1
  184. del a
  185. assert stats.alive() == 0
  186. def test_smart_ptr_from_default():
  187. from pybind11_tests.smart_ptr import HeldByDefaultHolder
  188. instance = HeldByDefaultHolder()
  189. with pytest.raises(RuntimeError) as excinfo:
  190. HeldByDefaultHolder.load_shared_ptr(instance)
  191. assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
  192. def test_shared_ptr_gc():
  193. """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
  194. from pybind11_tests.smart_ptr import ElementList, ElementA
  195. el = ElementList()
  196. for i in range(10):
  197. el.add(ElementA(i))
  198. pytest.gc_collect()
  199. for i, v in enumerate(el.get()):
  200. assert i == v.value()