blob: d275b3dc9bc5c6f546095ca7e0eedeff5683fc81 [file] [log] [blame]
Dean Moldovanab90ec62016-12-07 02:36:44 +01001import pytest
Jason Rhinelander391c7542017-07-25 16:47:36 -04002from pybind11_tests import smart_ptr as m
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02003from pybind11_tests import ConstructorStats
4
5
6def test_smart_ptr(capture):
7 # Object1
Jason Rhinelander391c7542017-07-25 16:47:36 -04008 for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02009 assert o.getRefCount() == 1
10 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040011 m.print_object_1(o)
12 m.print_object_2(o)
13 m.print_object_3(o)
14 m.print_object_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020015 assert capture == "MyObject1[{i}]\n".format(i=i) * 4
16
Jason Rhinelander391c7542017-07-25 16:47:36 -040017 for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
18 start=4):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020019 print(o)
20 with capture:
21 if not isinstance(o, int):
Jason Rhinelander391c7542017-07-25 16:47:36 -040022 m.print_object_1(o)
23 m.print_object_2(o)
24 m.print_object_3(o)
25 m.print_object_4(o)
26 m.print_myobject1_1(o)
27 m.print_myobject1_2(o)
28 m.print_myobject1_3(o)
29 m.print_myobject1_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020030 assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
31
Jason Rhinelander391c7542017-07-25 16:47:36 -040032 cstats = ConstructorStats.get(m.MyObject1)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020033 assert cstats.alive() == 0
34 expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
35 assert cstats.values() == expected_values
36 assert cstats.default_constructions == 0
37 assert cstats.copy_constructions == 0
38 # assert cstats.move_constructions >= 0 # Doesn't invoke any
39 assert cstats.copy_assignments == 0
40 assert cstats.move_assignments == 0
41
42 # Object2
Jason Rhinelander391c7542017-07-25 16:47:36 -040043 for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020044 print(o)
45 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040046 m.print_myobject2_1(o)
47 m.print_myobject2_2(o)
48 m.print_myobject2_3(o)
49 m.print_myobject2_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020050 assert capture == "MyObject2[{i}]\n".format(i=i) * 4
51
Jason Rhinelander391c7542017-07-25 16:47:36 -040052 cstats = ConstructorStats.get(m.MyObject2)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020053 assert cstats.alive() == 1
54 o = None
55 assert cstats.alive() == 0
56 assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
57 assert cstats.default_constructions == 0
58 assert cstats.copy_constructions == 0
59 # assert cstats.move_constructions >= 0 # Doesn't invoke any
60 assert cstats.copy_assignments == 0
61 assert cstats.move_assignments == 0
62
63 # Object3
Jason Rhinelander391c7542017-07-25 16:47:36 -040064 for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020065 print(o)
66 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040067 m.print_myobject3_1(o)
68 m.print_myobject3_2(o)
69 m.print_myobject3_3(o)
70 m.print_myobject3_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020071 assert capture == "MyObject3[{i}]\n".format(i=i) * 4
72
Jason Rhinelander391c7542017-07-25 16:47:36 -040073 cstats = ConstructorStats.get(m.MyObject3)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020074 assert cstats.alive() == 1
75 o = None
76 assert cstats.alive() == 0
77 assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
78 assert cstats.default_constructions == 0
79 assert cstats.copy_constructions == 0
80 # assert cstats.move_constructions >= 0 # Doesn't invoke any
81 assert cstats.copy_assignments == 0
82 assert cstats.move_assignments == 0
83
Jason Rhinelander391c7542017-07-25 16:47:36 -040084 # Object
85 cstats = ConstructorStats.get(m.Object)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020086 assert cstats.alive() == 0
87 assert cstats.values() == []
88 assert cstats.default_constructions == 10
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
Jason Rhinelander391c7542017-07-25 16:47:36 -040094 # ref<>
95 cstats = m.cstats_ref()
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020096 assert cstats.alive() == 0
97 assert cstats.values() == ['from pointer'] * 10
98 assert cstats.default_constructions == 30
99 assert cstats.copy_constructions == 12
100 # assert cstats.move_constructions >= 0 # Doesn't invoke any
101 assert cstats.copy_assignments == 30
102 assert cstats.move_assignments == 0
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400103
Dean Moldovanbad17402016-11-20 21:21:54 +0100104
Wenzel Jakob20291712016-12-15 23:44:23 +0100105def test_smart_ptr_refcounting():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400106 assert m.test_object1_refcounting()
Wenzel Jakob20291712016-12-15 23:44:23 +0100107
108
Dean Moldovanbad17402016-11-20 21:21:54 +0100109def test_unique_nodelete():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400110 o = m.MyObject4(23)
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400111 assert o.value == 23
Jason Rhinelander391c7542017-07-25 16:47:36 -0400112 cstats = ConstructorStats.get(m.MyObject4)
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400113 assert cstats.alive() == 1
114 del o
Dean Moldovanbad17402016-11-20 21:21:54 +0100115 assert cstats.alive() == 1 # Leak, but that's intentional
Dean Moldovanab90ec62016-12-07 02:36:44 +0100116
117
Trevor Laughlin63c2a972018-11-11 13:36:55 -0500118def test_unique_nodelete4a():
119 o = m.MyObject4a(23)
120 assert o.value == 23
121 cstats = ConstructorStats.get(m.MyObject4a)
122 assert cstats.alive() == 1
123 del o
124 assert cstats.alive() == 1 # Leak, but that's intentional
125
126
127def test_unique_deleter():
128 o = m.MyObject4b(23)
129 assert o.value == 23
130 cstats4a = ConstructorStats.get(m.MyObject4a)
luzpaz21bf16f2019-06-10 12:56:38 -0700131 assert cstats4a.alive() == 2 # Two because of previous test
Trevor Laughlin63c2a972018-11-11 13:36:55 -0500132 cstats4b = ConstructorStats.get(m.MyObject4b)
133 assert cstats4b.alive() == 1
134 del o
135 assert cstats4a.alive() == 1 # Should now only be one leftover from previous test
136 assert cstats4b.alive() == 0 # Should be deleted
137
138
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500139def test_large_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400140 o = m.MyObject5(5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500141 assert o.value == 5
Jason Rhinelander391c7542017-07-25 16:47:36 -0400142 cstats = ConstructorStats.get(m.MyObject5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500143 assert cstats.alive() == 1
144 del o
145 assert cstats.alive() == 0
146
147
Dean Moldovanab90ec62016-12-07 02:36:44 +0100148def test_shared_ptr_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400149 s = m.SharedPtrRef()
150 stats = ConstructorStats.get(m.A)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100151 assert stats.alive() == 2
152
153 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
154 assert stats.alive() == 2
155 assert s.set_ref(ref)
156 with pytest.raises(RuntimeError) as excinfo:
157 assert s.set_holder(ref)
158 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
159
160 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
161 assert stats.alive() == 3
162 assert s.set_ref(copy)
163 assert s.set_holder(copy)
164
165 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
166 assert stats.alive() == 3
167 assert s.set_ref(holder_ref)
168 assert s.set_holder(holder_ref)
169
170 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
171 assert stats.alive() == 3
172 assert s.set_ref(holder_copy)
173 assert s.set_holder(holder_copy)
174
175 del ref, copy, holder_ref, holder_copy, s
176 assert stats.alive() == 0
177
178
179def test_shared_ptr_from_this_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400180 s = m.SharedFromThisRef()
181 stats = ConstructorStats.get(m.B)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100182 assert stats.alive() == 2
183
184 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
185 assert stats.alive() == 2
186 assert s.set_ref(ref)
187 assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
188
189 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
190 assert stats.alive() == 2
191 assert s.set_ref(bad_wp)
192 with pytest.raises(RuntimeError) as excinfo:
193 assert s.set_holder(bad_wp)
194 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
195
196 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
197 assert stats.alive() == 3
198 assert s.set_ref(copy)
199 assert s.set_holder(copy)
200
201 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
202 assert stats.alive() == 3
203 assert s.set_ref(holder_ref)
204 assert s.set_holder(holder_ref)
205
206 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
207 assert stats.alive() == 3
208 assert s.set_ref(holder_copy)
209 assert s.set_holder(holder_copy)
210
211 del ref, bad_wp, copy, holder_ref, holder_copy, s
212 assert stats.alive() == 0
Dean Moldovanec009a72017-01-31 17:05:44 +0100213
Jason Rhinelander391c7542017-07-25 16:47:36 -0400214 z = m.SharedFromThisVirt.get()
215 y = m.SharedFromThisVirt.get()
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400216 assert y is z
217
Dean Moldovanec009a72017-01-31 17:05:44 +0100218
219def test_move_only_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400220 a = m.TypeWithMoveOnlyHolder.make()
Yannick Jadould54d6d82020-07-01 01:53:09 +0200221 b = m.TypeWithMoveOnlyHolder.make_as_object()
Jason Rhinelander391c7542017-07-25 16:47:36 -0400222 stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
Yannick Jadould54d6d82020-07-01 01:53:09 +0200223 assert stats.alive() == 2
224 del b
Dean Moldovanec009a72017-01-31 17:05:44 +0100225 assert stats.alive() == 1
226 del a
227 assert stats.alive() == 0
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100228
229
Khachajantc Michaele3cb2a62018-06-20 18:33:50 +0300230def test_holder_with_addressof_operator():
231 # this test must not throw exception from c++
232 a = m.TypeForHolderWithAddressOf.make()
233 a.print_object_1()
234 a.print_object_2()
235 a.print_object_3()
236 a.print_object_4()
237
238 stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
239 assert stats.alive() == 1
240
241 np = m.TypeForHolderWithAddressOf.make()
242 assert stats.alive() == 2
243 del a
244 assert stats.alive() == 1
245 del np
246 assert stats.alive() == 0
247
248 b = m.TypeForHolderWithAddressOf.make()
249 c = b
250 assert b.get() is c.get()
251 assert stats.alive() == 1
252
253 del b
254 assert stats.alive() == 1
255
256 del c
257 assert stats.alive() == 0
258
259
260def test_move_only_holder_with_addressof_operator():
261 a = m.TypeForMoveOnlyHolderWithAddressOf.make()
262 a.print_object()
263
264 stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
265 assert stats.alive() == 1
266
267 a.value = 42
268 assert a.value == 42
269
270 del a
271 assert stats.alive() == 0
272
273
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100274def test_smart_ptr_from_default():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400275 instance = m.HeldByDefaultHolder()
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100276 with pytest.raises(RuntimeError) as excinfo:
Jason Rhinelander391c7542017-07-25 16:47:36 -0400277 m.HeldByDefaultHolder.load_shared_ptr(instance)
Wenzel Jakob9fd47122019-07-06 16:57:17 +0200278 assert "Unable to load a custom holder type from a " \
279 "default-holder instance" in str(excinfo.value)
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200280
281
282def test_shared_ptr_gc():
283 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
Jason Rhinelander391c7542017-07-25 16:47:36 -0400284 el = m.ElementList()
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200285 for i in range(10):
Jason Rhinelander391c7542017-07-25 16:47:36 -0400286 el.add(m.ElementA(i))
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200287 pytest.gc_collect()
288 for i, v in enumerate(el.get()):
289 assert i == v.value()