μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
test_smart_ptr.py
Go to the documentation of this file.
1import pytest
2
3m = pytest.importorskip("pybind11_tests.smart_ptr")
4from pybind11_tests import ConstructorStats # noqa: E402
5
6
7def test_smart_ptr(capture):
8 # Object1
9 for i, o in enumerate(
10 [m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1
11 ):
12 assert o.getRefCount() == 1
13 with capture:
14 m.print_object_1(o)
15 m.print_object_2(o)
16 m.print_object_3(o)
17 m.print_object_4(o)
18 assert capture == f"MyObject1[{i}]\n" * 4
19
20 for i, o in enumerate(
21 [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
22 ):
23 print(o)
24 with capture:
25 if not isinstance(o, int):
26 m.print_object_1(o)
27 m.print_object_2(o)
28 m.print_object_3(o)
29 m.print_object_4(o)
30 m.print_myobject1_1(o)
31 m.print_myobject1_2(o)
32 m.print_myobject1_3(o)
33 m.print_myobject1_4(o)
34
35 times = 4 if isinstance(o, int) else 8
36 assert capture == f"MyObject1[{i}]\n" * times
37
38 cstats = ConstructorStats.get(m.MyObject1)
39 assert cstats.alive() == 0
40 expected_values = [f"MyObject1[{i}]" for i in range(1, 7)] + ["MyObject1[7]"] * 4
41 assert cstats.values() == expected_values
42 assert cstats.default_constructions == 0
43 assert cstats.copy_constructions == 0
44 # assert cstats.move_constructions >= 0 # Doesn't invoke any
45 assert cstats.copy_assignments == 0
46 assert cstats.move_assignments == 0
47
48 # Object2
49 for i, o in zip(
50 [8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]
51 ):
52 print(o)
53 with capture:
54 m.print_myobject2_1(o)
55 m.print_myobject2_2(o)
56 m.print_myobject2_3(o)
57 m.print_myobject2_4(o)
58 assert capture == f"MyObject2[{i}]\n" * 4
59
60 cstats = ConstructorStats.get(m.MyObject2)
61 assert cstats.alive() == 1
62 o = None
63 assert cstats.alive() == 0
64 assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
65 assert cstats.default_constructions == 0
66 assert cstats.copy_constructions == 0
67 # assert cstats.move_constructions >= 0 # Doesn't invoke any
68 assert cstats.copy_assignments == 0
69 assert cstats.move_assignments == 0
70
71 # Object3
72 for i, o in zip(
73 [9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]
74 ):
75 print(o)
76 with capture:
77 m.print_myobject3_1(o)
78 m.print_myobject3_2(o)
79 m.print_myobject3_3(o)
80 m.print_myobject3_4(o)
81 assert capture == f"MyObject3[{i}]\n" * 4
82
83 cstats = ConstructorStats.get(m.MyObject3)
84 assert cstats.alive() == 1
85 o = None
86 assert cstats.alive() == 0
87 assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]
88 assert cstats.default_constructions == 0
89 assert cstats.copy_constructions == 0
90 # assert cstats.move_constructions >= 0 # Doesn't invoke any
91 assert cstats.copy_assignments == 0
92 assert cstats.move_assignments == 0
93
94 # Object
95 cstats = ConstructorStats.get(m.Object)
96 assert cstats.alive() == 0
97 assert cstats.values() == []
98 assert cstats.default_constructions == 10
99 assert cstats.copy_constructions == 0
100 # assert cstats.move_constructions >= 0 # Doesn't invoke any
101 assert cstats.copy_assignments == 0
102 assert cstats.move_assignments == 0
103
104 # ref<>
105 cstats = m.cstats_ref()
106 assert cstats.alive() == 0
107 assert cstats.values() == ["from pointer"] * 10
108 assert cstats.default_constructions == 30
109 assert cstats.copy_constructions == 12
110 # assert cstats.move_constructions >= 0 # Doesn't invoke any
111 assert cstats.copy_assignments == 30
112 assert cstats.move_assignments == 0
113
114
115def test_smart_ptr_refcounting():
116 assert m.test_object1_refcounting()
117
118
119def test_unique_nodelete():
120 o = m.MyObject4(23)
121 assert o.value == 23
122 cstats = ConstructorStats.get(m.MyObject4)
123 assert cstats.alive() == 1
124 del o
125 assert cstats.alive() == 1
126 m.MyObject4.cleanup_all_instances()
127 assert cstats.alive() == 0
128
129
130def test_unique_nodelete4a():
131 o = m.MyObject4a(23)
132 assert o.value == 23
133 cstats = ConstructorStats.get(m.MyObject4a)
134 assert cstats.alive() == 1
135 del o
136 assert cstats.alive() == 1
137 m.MyObject4a.cleanup_all_instances()
138 assert cstats.alive() == 0
139
140
141def test_unique_deleter():
142 m.MyObject4a(0)
143 o = m.MyObject4b(23)
144 assert o.value == 23
145 cstats4a = ConstructorStats.get(m.MyObject4a)
146 assert cstats4a.alive() == 2
147 cstats4b = ConstructorStats.get(m.MyObject4b)
148 assert cstats4b.alive() == 1
149 del o
150 assert cstats4a.alive() == 1 # Should now only be one leftover
151 assert cstats4b.alive() == 0 # Should be deleted
152 m.MyObject4a.cleanup_all_instances()
153 assert cstats4a.alive() == 0
154 assert cstats4b.alive() == 0
155
156
157def test_large_holder():
158 o = m.MyObject5(5)
159 assert o.value == 5
160 cstats = ConstructorStats.get(m.MyObject5)
161 assert cstats.alive() == 1
162 del o
163 assert cstats.alive() == 0
164
165
166def test_shared_ptr_and_references():
167 s = m.SharedPtrRef()
168 stats = ConstructorStats.get(m.A)
169 assert stats.alive() == 2
170
171 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
172 assert stats.alive() == 2
173 assert s.set_ref(ref)
174 with pytest.raises(RuntimeError) as excinfo:
175 assert s.set_holder(ref)
176 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
177
178 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
179 assert stats.alive() == 3
180 assert s.set_ref(copy)
181 assert s.set_holder(copy)
182
183 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
184 assert stats.alive() == 3
185 assert s.set_ref(holder_ref)
186 assert s.set_holder(holder_ref)
187
188 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
189 assert stats.alive() == 3
190 assert s.set_ref(holder_copy)
191 assert s.set_holder(holder_copy)
192
193 del ref, copy, holder_ref, holder_copy, s
194 assert stats.alive() == 0
195
196
197def test_shared_ptr_from_this_and_references():
198 s = m.SharedFromThisRef()
199 stats = ConstructorStats.get(m.B)
200 assert stats.alive() == 2
201
202 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
203 assert stats.alive() == 2
204 assert s.set_ref(ref)
205 assert s.set_holder(
206 ref
207 ) # std::enable_shared_from_this can create a holder from a reference
208
209 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
210 assert stats.alive() == 2
211 assert s.set_ref(bad_wp)
212 with pytest.raises(RuntimeError) as excinfo:
213 assert s.set_holder(bad_wp)
214 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
215
216 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
217 assert stats.alive() == 3
218 assert s.set_ref(copy)
219 assert s.set_holder(copy)
220
221 holder_ref = (
222 s.holder_ref
223 ) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
224 assert stats.alive() == 3
225 assert s.set_ref(holder_ref)
226 assert s.set_holder(holder_ref)
227
228 holder_copy = (
229 s.holder_copy
230 ) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
231 assert stats.alive() == 3
232 assert s.set_ref(holder_copy)
233 assert s.set_holder(holder_copy)
234
235 del ref, bad_wp, copy, holder_ref, holder_copy, s
236 assert stats.alive() == 0
237
238 z = m.SharedFromThisVirt.get()
239 y = m.SharedFromThisVirt.get()
240 assert y is z
241
242
243def test_move_only_holder():
244 a = m.TypeWithMoveOnlyHolder.make()
245 b = m.TypeWithMoveOnlyHolder.make_as_object()
246 stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
247 assert stats.alive() == 2
248 del b
249 assert stats.alive() == 1
250 del a
251 assert stats.alive() == 0
252
253
254def test_holder_with_addressof_operator():
255 # this test must not throw exception from c++
256 a = m.TypeForHolderWithAddressOf.make()
257 a.print_object_1()
258 a.print_object_2()
259 a.print_object_3()
260 a.print_object_4()
261
262 stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
263 assert stats.alive() == 1
264
265 np = m.TypeForHolderWithAddressOf.make()
266 assert stats.alive() == 2
267 del a
268 assert stats.alive() == 1
269 del np
270 assert stats.alive() == 0
271
272 b = m.TypeForHolderWithAddressOf.make()
273 c = b
274 assert b.get() is c.get()
275 assert stats.alive() == 1
276
277 del b
278 assert stats.alive() == 1
279
280 del c
281 assert stats.alive() == 0
282
283
284def test_move_only_holder_with_addressof_operator():
285 a = m.TypeForMoveOnlyHolderWithAddressOf.make()
286 a.print_object()
287
288 stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
289 assert stats.alive() == 1
290
291 a.value = 42
292 assert a.value == 42
293
294 del a
295 assert stats.alive() == 0
296
297
298def test_smart_ptr_from_default():
299 instance = m.HeldByDefaultHolder()
300 with pytest.raises(RuntimeError) as excinfo:
301 m.HeldByDefaultHolder.load_shared_ptr(instance)
302 assert (
303 "Unable to load a custom holder type from a "
304 "default-holder instance" in str(excinfo.value)
305 )
306
307
308def test_shared_ptr_gc():
309 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
310 el = m.ElementList()
311 for i in range(10):
312 el.add(m.ElementA(i))
313 pytest.gc_collect()
314 for i, v in enumerate(el.get()):
315 assert i == v.value()
static ConstructorStats & get(std::type_index type)
Definition: pytypes.h:1200
bool isinstance(handle obj)
\rst Return true if obj is an instance of T.
Definition: pytypes.h:489