File indexing completed on 2025-01-18 10:17:57
0001 import pytest
0002
0003 m = pytest.importorskip("pybind11_tests.smart_ptr")
0004 from pybind11_tests import ConstructorStats
0005
0006
0007 def test_smart_ptr(capture):
0008
0009 for i, o in enumerate(
0010 [m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1
0011 ):
0012 assert o.getRefCount() == 1
0013 with capture:
0014 m.print_object_1(o)
0015 m.print_object_2(o)
0016 m.print_object_3(o)
0017 m.print_object_4(o)
0018 assert capture == f"MyObject1[{i}]\n" * 4
0019
0020 for i, o in enumerate(
0021 [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
0022 ):
0023 print(o)
0024 with capture:
0025 if not isinstance(o, int):
0026 m.print_object_1(o)
0027 m.print_object_2(o)
0028 m.print_object_3(o)
0029 m.print_object_4(o)
0030 m.print_myobject1_1(o)
0031 m.print_myobject1_2(o)
0032 m.print_myobject1_3(o)
0033 m.print_myobject1_4(o)
0034
0035 times = 4 if isinstance(o, int) else 8
0036 assert capture == f"MyObject1[{i}]\n" * times
0037
0038 cstats = ConstructorStats.get(m.MyObject1)
0039 assert cstats.alive() == 0
0040 expected_values = [f"MyObject1[{i}]" for i in range(1, 7)] + ["MyObject1[7]"] * 4
0041 assert cstats.values() == expected_values
0042 assert cstats.default_constructions == 0
0043 assert cstats.copy_constructions == 0
0044
0045 assert cstats.copy_assignments == 0
0046 assert cstats.move_assignments == 0
0047
0048
0049 for i, o in zip(
0050 [8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]
0051 ):
0052 print(o)
0053 with capture:
0054 m.print_myobject2_1(o)
0055 m.print_myobject2_2(o)
0056 m.print_myobject2_3(o)
0057 m.print_myobject2_4(o)
0058 assert capture == f"MyObject2[{i}]\n" * 4
0059
0060 cstats = ConstructorStats.get(m.MyObject2)
0061 assert cstats.alive() == 1
0062 o = None
0063 assert cstats.alive() == 0
0064 assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
0065 assert cstats.default_constructions == 0
0066 assert cstats.copy_constructions == 0
0067
0068 assert cstats.copy_assignments == 0
0069 assert cstats.move_assignments == 0
0070
0071
0072 for i, o in zip(
0073 [9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]
0074 ):
0075 print(o)
0076 with capture:
0077 m.print_myobject3_1(o)
0078 m.print_myobject3_2(o)
0079 m.print_myobject3_3(o)
0080 m.print_myobject3_4(o)
0081 assert capture == f"MyObject3[{i}]\n" * 4
0082
0083 cstats = ConstructorStats.get(m.MyObject3)
0084 assert cstats.alive() == 1
0085 o = None
0086 assert cstats.alive() == 0
0087 assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]
0088 assert cstats.default_constructions == 0
0089 assert cstats.copy_constructions == 0
0090
0091 assert cstats.copy_assignments == 0
0092 assert cstats.move_assignments == 0
0093
0094
0095 cstats = ConstructorStats.get(m.Object)
0096 assert cstats.alive() == 0
0097 assert cstats.values() == []
0098 assert cstats.default_constructions == 10
0099 assert cstats.copy_constructions == 0
0100
0101 assert cstats.copy_assignments == 0
0102 assert cstats.move_assignments == 0
0103
0104
0105 cstats = m.cstats_ref()
0106 assert cstats.alive() == 0
0107 assert cstats.values() == ["from pointer"] * 10
0108 assert cstats.default_constructions == 30
0109 assert cstats.copy_constructions == 12
0110
0111 assert cstats.copy_assignments == 30
0112 assert cstats.move_assignments == 0
0113
0114
0115 def test_smart_ptr_refcounting():
0116 assert m.test_object1_refcounting()
0117
0118
0119 def test_unique_nodelete():
0120 o = m.MyObject4(23)
0121 assert o.value == 23
0122 cstats = ConstructorStats.get(m.MyObject4)
0123 assert cstats.alive() == 1
0124 del o
0125 assert cstats.alive() == 1
0126 m.MyObject4.cleanup_all_instances()
0127 assert cstats.alive() == 0
0128
0129
0130 def test_unique_nodelete4a():
0131 o = m.MyObject4a(23)
0132 assert o.value == 23
0133 cstats = ConstructorStats.get(m.MyObject4a)
0134 assert cstats.alive() == 1
0135 del o
0136 assert cstats.alive() == 1
0137 m.MyObject4a.cleanup_all_instances()
0138 assert cstats.alive() == 0
0139
0140
0141 def test_unique_deleter():
0142 m.MyObject4a(0)
0143 o = m.MyObject4b(23)
0144 assert o.value == 23
0145 cstats4a = ConstructorStats.get(m.MyObject4a)
0146 assert cstats4a.alive() == 2
0147 cstats4b = ConstructorStats.get(m.MyObject4b)
0148 assert cstats4b.alive() == 1
0149 del o
0150 assert cstats4a.alive() == 1
0151 assert cstats4b.alive() == 0
0152 m.MyObject4a.cleanup_all_instances()
0153 assert cstats4a.alive() == 0
0154 assert cstats4b.alive() == 0
0155
0156
0157 def test_large_holder():
0158 o = m.MyObject5(5)
0159 assert o.value == 5
0160 cstats = ConstructorStats.get(m.MyObject5)
0161 assert cstats.alive() == 1
0162 del o
0163 assert cstats.alive() == 0
0164
0165
0166 def test_shared_ptr_and_references():
0167 s = m.SharedPtrRef()
0168 stats = ConstructorStats.get(m.A)
0169 assert stats.alive() == 2
0170
0171 ref = s.ref
0172 assert stats.alive() == 2
0173 assert s.set_ref(ref)
0174 with pytest.raises(RuntimeError) as excinfo:
0175 assert s.set_holder(ref)
0176 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
0177
0178 copy = s.copy
0179 assert stats.alive() == 3
0180 assert s.set_ref(copy)
0181 assert s.set_holder(copy)
0182
0183 holder_ref = s.holder_ref
0184 assert stats.alive() == 3
0185 assert s.set_ref(holder_ref)
0186 assert s.set_holder(holder_ref)
0187
0188 holder_copy = s.holder_copy
0189 assert stats.alive() == 3
0190 assert s.set_ref(holder_copy)
0191 assert s.set_holder(holder_copy)
0192
0193 del ref, copy, holder_ref, holder_copy, s
0194 assert stats.alive() == 0
0195
0196
0197 def test_shared_ptr_from_this_and_references():
0198 s = m.SharedFromThisRef()
0199 stats = ConstructorStats.get(m.B)
0200 assert stats.alive() == 2
0201
0202 ref = s.ref
0203 assert stats.alive() == 2
0204 assert s.set_ref(ref)
0205 assert s.set_holder(
0206 ref
0207 )
0208
0209 bad_wp = s.bad_wp
0210 assert stats.alive() == 2
0211 assert s.set_ref(bad_wp)
0212 with pytest.raises(RuntimeError) as excinfo:
0213 assert s.set_holder(bad_wp)
0214 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
0215
0216 copy = s.copy
0217 assert stats.alive() == 3
0218 assert s.set_ref(copy)
0219 assert s.set_holder(copy)
0220
0221 holder_ref = (
0222 s.holder_ref
0223 )
0224 assert stats.alive() == 3
0225 assert s.set_ref(holder_ref)
0226 assert s.set_holder(holder_ref)
0227
0228 holder_copy = (
0229 s.holder_copy
0230 )
0231 assert stats.alive() == 3
0232 assert s.set_ref(holder_copy)
0233 assert s.set_holder(holder_copy)
0234
0235 del ref, bad_wp, copy, holder_ref, holder_copy, s
0236 assert stats.alive() == 0
0237
0238 z = m.SharedFromThisVirt.get()
0239 y = m.SharedFromThisVirt.get()
0240 assert y is z
0241
0242
0243 def test_move_only_holder():
0244 a = m.TypeWithMoveOnlyHolder.make()
0245 b = m.TypeWithMoveOnlyHolder.make_as_object()
0246 stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
0247 assert stats.alive() == 2
0248 del b
0249 assert stats.alive() == 1
0250 del a
0251 assert stats.alive() == 0
0252
0253
0254 def test_holder_with_addressof_operator():
0255
0256 a = m.TypeForHolderWithAddressOf.make()
0257 a.print_object_1()
0258 a.print_object_2()
0259 a.print_object_3()
0260 a.print_object_4()
0261
0262 stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
0263 assert stats.alive() == 1
0264
0265 np = m.TypeForHolderWithAddressOf.make()
0266 assert stats.alive() == 2
0267 del a
0268 assert stats.alive() == 1
0269 del np
0270 assert stats.alive() == 0
0271
0272 b = m.TypeForHolderWithAddressOf.make()
0273 c = b
0274 assert b.get() is c.get()
0275 assert stats.alive() == 1
0276
0277 del b
0278 assert stats.alive() == 1
0279
0280 del c
0281 assert stats.alive() == 0
0282
0283
0284 def test_move_only_holder_with_addressof_operator():
0285 a = m.TypeForMoveOnlyHolderWithAddressOf.make()
0286 a.print_object()
0287
0288 stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
0289 assert stats.alive() == 1
0290
0291 a.value = 42
0292 assert a.value == 42
0293
0294 del a
0295 assert stats.alive() == 0
0296
0297
0298 def test_smart_ptr_from_default():
0299 instance = m.HeldByDefaultHolder()
0300 with pytest.raises(RuntimeError) as excinfo:
0301 m.HeldByDefaultHolder.load_shared_ptr(instance)
0302 assert (
0303 "Unable to load a custom holder type from a "
0304 "default-holder instance" in str(excinfo.value)
0305 )
0306
0307
0308 def test_shared_ptr_gc():
0309 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
0310 el = m.ElementList()
0311 for i in range(10):
0312 el.add(m.ElementA(i))
0313 pytest.gc_collect()
0314 for i, v in enumerate(el.get()):
0315 assert i == v.value()