blob: c9267f6878f1c0d912017bd2a6b0d21dd673c32b [file] [log] [blame]
Henry Schreinerd8c7ee02020-07-20 13:35:21 -04001# -*- coding: utf-8 -*-
Dean Moldovanab90ec62016-12-07 02:36:44 +01002import pytest
Jason Rhinelander391c7542017-07-25 16:47:36 -04003from pybind11_tests import smart_ptr as m
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02004from pybind11_tests import ConstructorStats
5
6
7def test_smart_ptr(capture):
8 # Object1
Jason Rhinelander391c7542017-07-25 16:47:36 -04009 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 +020010 assert o.getRefCount() == 1
11 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040012 m.print_object_1(o)
13 m.print_object_2(o)
14 m.print_object_3(o)
15 m.print_object_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020016 assert capture == "MyObject1[{i}]\n".format(i=i) * 4
17
Jason Rhinelander391c7542017-07-25 16:47:36 -040018 for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
19 start=4):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020020 print(o)
21 with capture:
22 if not isinstance(o, int):
Jason Rhinelander391c7542017-07-25 16:47:36 -040023 m.print_object_1(o)
24 m.print_object_2(o)
25 m.print_object_3(o)
26 m.print_object_4(o)
27 m.print_myobject1_1(o)
28 m.print_myobject1_2(o)
29 m.print_myobject1_3(o)
30 m.print_myobject1_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020031 assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
32
Jason Rhinelander391c7542017-07-25 16:47:36 -040033 cstats = ConstructorStats.get(m.MyObject1)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020034 assert cstats.alive() == 0
35 expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
36 assert cstats.values() == expected_values
37 assert cstats.default_constructions == 0
38 assert cstats.copy_constructions == 0
39 # assert cstats.move_constructions >= 0 # Doesn't invoke any
40 assert cstats.copy_assignments == 0
41 assert cstats.move_assignments == 0
42
43 # Object2
Jason Rhinelander391c7542017-07-25 16:47:36 -040044 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 +020045 print(o)
46 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040047 m.print_myobject2_1(o)
48 m.print_myobject2_2(o)
49 m.print_myobject2_3(o)
50 m.print_myobject2_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020051 assert capture == "MyObject2[{i}]\n".format(i=i) * 4
52
Jason Rhinelander391c7542017-07-25 16:47:36 -040053 cstats = ConstructorStats.get(m.MyObject2)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020054 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
64 # Object3
Jason Rhinelander391c7542017-07-25 16:47:36 -040065 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 +020066 print(o)
67 with capture:
Jason Rhinelander391c7542017-07-25 16:47:36 -040068 m.print_myobject3_1(o)
69 m.print_myobject3_2(o)
70 m.print_myobject3_3(o)
71 m.print_myobject3_4(o)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020072 assert capture == "MyObject3[{i}]\n".format(i=i) * 4
73
Jason Rhinelander391c7542017-07-25 16:47:36 -040074 cstats = ConstructorStats.get(m.MyObject3)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020075 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
Jason Rhinelander391c7542017-07-25 16:47:36 -040085 # Object
86 cstats = ConstructorStats.get(m.Object)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020087 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
Jason Rhinelander391c7542017-07-25 16:47:36 -040095 # ref<>
96 cstats = m.cstats_ref()
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020097 assert cstats.alive() == 0
98 assert cstats.values() == ['from pointer'] * 10
99 assert cstats.default_constructions == 30
100 assert cstats.copy_constructions == 12
101 # assert cstats.move_constructions >= 0 # Doesn't invoke any
102 assert cstats.copy_assignments == 30
103 assert cstats.move_assignments == 0
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400104
Dean Moldovanbad17402016-11-20 21:21:54 +0100105
Wenzel Jakob20291712016-12-15 23:44:23 +0100106def test_smart_ptr_refcounting():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400107 assert m.test_object1_refcounting()
Wenzel Jakob20291712016-12-15 23:44:23 +0100108
109
Dean Moldovanbad17402016-11-20 21:21:54 +0100110def test_unique_nodelete():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400111 o = m.MyObject4(23)
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400112 assert o.value == 23
Jason Rhinelander391c7542017-07-25 16:47:36 -0400113 cstats = ConstructorStats.get(m.MyObject4)
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400114 assert cstats.alive() == 1
115 del o
Dean Moldovanbad17402016-11-20 21:21:54 +0100116 assert cstats.alive() == 1 # Leak, but that's intentional
Dean Moldovanab90ec62016-12-07 02:36:44 +0100117
118
Trevor Laughlin63c2a972018-11-11 13:36:55 -0500119def test_unique_nodelete4a():
120 o = m.MyObject4a(23)
121 assert o.value == 23
122 cstats = ConstructorStats.get(m.MyObject4a)
123 assert cstats.alive() == 1
124 del o
125 assert cstats.alive() == 1 # Leak, but that's intentional
126
127
128def test_unique_deleter():
129 o = m.MyObject4b(23)
130 assert o.value == 23
131 cstats4a = ConstructorStats.get(m.MyObject4a)
luzpaz21bf16f2019-06-10 12:56:38 -0700132 assert cstats4a.alive() == 2 # Two because of previous test
Trevor Laughlin63c2a972018-11-11 13:36:55 -0500133 cstats4b = ConstructorStats.get(m.MyObject4b)
134 assert cstats4b.alive() == 1
135 del o
136 assert cstats4a.alive() == 1 # Should now only be one leftover from previous test
137 assert cstats4b.alive() == 0 # Should be deleted
138
139
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500140def test_large_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400141 o = m.MyObject5(5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500142 assert o.value == 5
Jason Rhinelander391c7542017-07-25 16:47:36 -0400143 cstats = ConstructorStats.get(m.MyObject5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500144 assert cstats.alive() == 1
145 del o
146 assert cstats.alive() == 0
147
148
Dean Moldovanab90ec62016-12-07 02:36:44 +0100149def test_shared_ptr_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400150 s = m.SharedPtrRef()
151 stats = ConstructorStats.get(m.A)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100152 assert stats.alive() == 2
153
154 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
155 assert stats.alive() == 2
156 assert s.set_ref(ref)
157 with pytest.raises(RuntimeError) as excinfo:
158 assert s.set_holder(ref)
159 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
160
161 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
162 assert stats.alive() == 3
163 assert s.set_ref(copy)
164 assert s.set_holder(copy)
165
166 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
167 assert stats.alive() == 3
168 assert s.set_ref(holder_ref)
169 assert s.set_holder(holder_ref)
170
171 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
172 assert stats.alive() == 3
173 assert s.set_ref(holder_copy)
174 assert s.set_holder(holder_copy)
175
176 del ref, copy, holder_ref, holder_copy, s
177 assert stats.alive() == 0
178
179
180def test_shared_ptr_from_this_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400181 s = m.SharedFromThisRef()
182 stats = ConstructorStats.get(m.B)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100183 assert stats.alive() == 2
184
185 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
186 assert stats.alive() == 2
187 assert s.set_ref(ref)
188 assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
189
190 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
191 assert stats.alive() == 2
192 assert s.set_ref(bad_wp)
193 with pytest.raises(RuntimeError) as excinfo:
194 assert s.set_holder(bad_wp)
195 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
196
197 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
198 assert stats.alive() == 3
199 assert s.set_ref(copy)
200 assert s.set_holder(copy)
201
202 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
203 assert stats.alive() == 3
204 assert s.set_ref(holder_ref)
205 assert s.set_holder(holder_ref)
206
207 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
208 assert stats.alive() == 3
209 assert s.set_ref(holder_copy)
210 assert s.set_holder(holder_copy)
211
212 del ref, bad_wp, copy, holder_ref, holder_copy, s
213 assert stats.alive() == 0
Dean Moldovanec009a72017-01-31 17:05:44 +0100214
Jason Rhinelander391c7542017-07-25 16:47:36 -0400215 z = m.SharedFromThisVirt.get()
216 y = m.SharedFromThisVirt.get()
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400217 assert y is z
218
Dean Moldovanec009a72017-01-31 17:05:44 +0100219
220def test_move_only_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400221 a = m.TypeWithMoveOnlyHolder.make()
Yannick Jadould54d6d82020-07-01 01:53:09 +0200222 b = m.TypeWithMoveOnlyHolder.make_as_object()
Jason Rhinelander391c7542017-07-25 16:47:36 -0400223 stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
Yannick Jadould54d6d82020-07-01 01:53:09 +0200224 assert stats.alive() == 2
225 del b
Dean Moldovanec009a72017-01-31 17:05:44 +0100226 assert stats.alive() == 1
227 del a
228 assert stats.alive() == 0
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100229
230
Khachajantc Michaele3cb2a62018-06-20 18:33:50 +0300231def test_holder_with_addressof_operator():
232 # this test must not throw exception from c++
233 a = m.TypeForHolderWithAddressOf.make()
234 a.print_object_1()
235 a.print_object_2()
236 a.print_object_3()
237 a.print_object_4()
238
239 stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
240 assert stats.alive() == 1
241
242 np = m.TypeForHolderWithAddressOf.make()
243 assert stats.alive() == 2
244 del a
245 assert stats.alive() == 1
246 del np
247 assert stats.alive() == 0
248
249 b = m.TypeForHolderWithAddressOf.make()
250 c = b
251 assert b.get() is c.get()
252 assert stats.alive() == 1
253
254 del b
255 assert stats.alive() == 1
256
257 del c
258 assert stats.alive() == 0
259
260
261def test_move_only_holder_with_addressof_operator():
262 a = m.TypeForMoveOnlyHolderWithAddressOf.make()
263 a.print_object()
264
265 stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
266 assert stats.alive() == 1
267
268 a.value = 42
269 assert a.value == 42
270
271 del a
272 assert stats.alive() == 0
273
274
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100275def test_smart_ptr_from_default():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400276 instance = m.HeldByDefaultHolder()
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100277 with pytest.raises(RuntimeError) as excinfo:
Jason Rhinelander391c7542017-07-25 16:47:36 -0400278 m.HeldByDefaultHolder.load_shared_ptr(instance)
Wenzel Jakob9fd47122019-07-06 16:57:17 +0200279 assert "Unable to load a custom holder type from a " \
280 "default-holder instance" in str(excinfo.value)
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200281
282
283def test_shared_ptr_gc():
284 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
Jason Rhinelander391c7542017-07-25 16:47:36 -0400285 el = m.ElementList()
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200286 for i in range(10):
Jason Rhinelander391c7542017-07-25 16:47:36 -0400287 el.add(m.ElementA(i))
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200288 pytest.gc_collect()
289 for i, v in enumerate(el.get()):
290 assert i == v.value()