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.

198 lines
7.2 KiB

  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_unique_nodelete():
  103. from pybind11_tests import MyObject4
  104. o = MyObject4(23)
  105. assert o.value == 23
  106. cstats = ConstructorStats.get(MyObject4)
  107. assert cstats.alive() == 1
  108. del o
  109. cstats = ConstructorStats.get(MyObject4)
  110. assert cstats.alive() == 1 # Leak, but that's intentional
  111. def test_shared_ptr_and_references():
  112. from pybind11_tests.smart_ptr import SharedPtrRef, A
  113. s = SharedPtrRef()
  114. stats = ConstructorStats.get(A)
  115. assert stats.alive() == 2
  116. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
  117. assert stats.alive() == 2
  118. assert s.set_ref(ref)
  119. with pytest.raises(RuntimeError) as excinfo:
  120. assert s.set_holder(ref)
  121. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  122. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
  123. assert stats.alive() == 3
  124. assert s.set_ref(copy)
  125. assert s.set_holder(copy)
  126. holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
  127. assert stats.alive() == 3
  128. assert s.set_ref(holder_ref)
  129. assert s.set_holder(holder_ref)
  130. holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
  131. assert stats.alive() == 3
  132. assert s.set_ref(holder_copy)
  133. assert s.set_holder(holder_copy)
  134. del ref, copy, holder_ref, holder_copy, s
  135. assert stats.alive() == 0
  136. def test_shared_ptr_from_this_and_references():
  137. from pybind11_tests.smart_ptr import SharedFromThisRef, B
  138. s = SharedFromThisRef()
  139. stats = ConstructorStats.get(B)
  140. assert stats.alive() == 2
  141. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
  142. assert stats.alive() == 2
  143. assert s.set_ref(ref)
  144. assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
  145. bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
  146. assert stats.alive() == 2
  147. assert s.set_ref(bad_wp)
  148. with pytest.raises(RuntimeError) as excinfo:
  149. assert s.set_holder(bad_wp)
  150. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  151. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
  152. assert stats.alive() == 3
  153. assert s.set_ref(copy)
  154. assert s.set_holder(copy)
  155. holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
  156. assert stats.alive() == 3
  157. assert s.set_ref(holder_ref)
  158. assert s.set_holder(holder_ref)
  159. holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
  160. assert stats.alive() == 3
  161. assert s.set_ref(holder_copy)
  162. assert s.set_holder(holder_copy)
  163. del ref, bad_wp, copy, holder_ref, holder_copy, s
  164. assert stats.alive() == 0