blob: 144180d8ca97633e18111c5ab14b72edb2fc7b0b [file] [log] [blame]
Dean Moldovanab90ec62016-12-07 02:36:44 +01001import pytest
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002from pybind11_tests import ConstructorStats
3
4
5def test_smart_ptr(capture):
6 # Object1
7 from pybind11_tests import (MyObject1, make_object_1, make_object_2,
8 print_object_1, print_object_2, print_object_3, print_object_4)
9
10 for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1):
11 assert o.getRefCount() == 1
12 with capture:
13 print_object_1(o)
14 print_object_2(o)
15 print_object_3(o)
16 print_object_4(o)
17 assert capture == "MyObject1[{i}]\n".format(i=i) * 4
18
19 from pybind11_tests import (make_myobject1_1, make_myobject1_2,
20 print_myobject1_1, print_myobject1_2,
21 print_myobject1_3, print_myobject1_4)
22
23 for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4):
24 print(o)
25 with capture:
26 if not isinstance(o, int):
27 print_object_1(o)
28 print_object_2(o)
29 print_object_3(o)
30 print_object_4(o)
31 print_myobject1_1(o)
32 print_myobject1_2(o)
33 print_myobject1_3(o)
34 print_myobject1_4(o)
35 assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
36
37 cstats = ConstructorStats.get(MyObject1)
38 assert cstats.alive() == 0
39 expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
40 assert cstats.values() == expected_values
41 assert cstats.default_constructions == 0
42 assert cstats.copy_constructions == 0
43 # assert cstats.move_constructions >= 0 # Doesn't invoke any
44 assert cstats.copy_assignments == 0
45 assert cstats.move_assignments == 0
46
47 # Object2
48 from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2,
49 make_myobject3_1, make_myobject3_2,
50 print_myobject2_1, print_myobject2_2,
51 print_myobject2_3, print_myobject2_4)
52
53 for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]):
54 print(o)
55 with capture:
56 print_myobject2_1(o)
57 print_myobject2_2(o)
58 print_myobject2_3(o)
59 print_myobject2_4(o)
60 assert capture == "MyObject2[{i}]\n".format(i=i) * 4
61
62 cstats = ConstructorStats.get(MyObject2)
63 assert cstats.alive() == 1
64 o = None
65 assert cstats.alive() == 0
66 assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
67 assert cstats.default_constructions == 0
68 assert cstats.copy_constructions == 0
69 # assert cstats.move_constructions >= 0 # Doesn't invoke any
70 assert cstats.copy_assignments == 0
71 assert cstats.move_assignments == 0
72
73 # Object3
74 from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2,
75 print_myobject3_3, print_myobject3_4)
76
77 for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]):
78 print(o)
79 with capture:
80 print_myobject3_1(o)
81 print_myobject3_2(o)
82 print_myobject3_3(o)
83 print_myobject3_4(o)
84 assert capture == "MyObject3[{i}]\n".format(i=i) * 4
85
86 cstats = ConstructorStats.get(MyObject3)
87 assert cstats.alive() == 1
88 o = None
89 assert cstats.alive() == 0
90 assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
91 assert cstats.default_constructions == 0
92 assert cstats.copy_constructions == 0
93 # assert cstats.move_constructions >= 0 # Doesn't invoke any
94 assert cstats.copy_assignments == 0
95 assert cstats.move_assignments == 0
96
97 # Object and ref
98 from pybind11_tests import Object, cstats_ref
99
100 cstats = ConstructorStats.get(Object)
101 assert cstats.alive() == 0
102 assert cstats.values() == []
103 assert cstats.default_constructions == 10
104 assert cstats.copy_constructions == 0
105 # assert cstats.move_constructions >= 0 # Doesn't invoke any
106 assert cstats.copy_assignments == 0
107 assert cstats.move_assignments == 0
108
109 cstats = cstats_ref()
110 assert cstats.alive() == 0
111 assert cstats.values() == ['from pointer'] * 10
112 assert cstats.default_constructions == 30
113 assert cstats.copy_constructions == 12
114 # assert cstats.move_constructions >= 0 # Doesn't invoke any
115 assert cstats.copy_assignments == 30
116 assert cstats.move_assignments == 0
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400117
Dean Moldovanbad17402016-11-20 21:21:54 +0100118
Wenzel Jakob20291712016-12-15 23:44:23 +0100119def test_smart_ptr_refcounting():
120 from pybind11_tests import test_object1_refcounting
121 assert test_object1_refcounting()
122
123
Dean Moldovanbad17402016-11-20 21:21:54 +0100124def test_unique_nodelete():
Jason Rhinelandera6495af2016-09-04 18:23:55 -0400125 from pybind11_tests import MyObject4
126 o = MyObject4(23)
127 assert o.value == 23
128 cstats = ConstructorStats.get(MyObject4)
129 assert cstats.alive() == 1
130 del o
131 cstats = ConstructorStats.get(MyObject4)
Dean Moldovanbad17402016-11-20 21:21:54 +0100132 assert cstats.alive() == 1 # Leak, but that's intentional
Dean Moldovanab90ec62016-12-07 02:36:44 +0100133
134
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500135def test_large_holder():
136 from pybind11_tests import MyObject5
137 o = MyObject5(5)
138 assert o.value == 5
139 cstats = ConstructorStats.get(MyObject5)
140 assert cstats.alive() == 1
141 del o
142 assert cstats.alive() == 0
143
144
Dean Moldovanab90ec62016-12-07 02:36:44 +0100145def test_shared_ptr_and_references():
146 from pybind11_tests.smart_ptr import SharedPtrRef, A
147
148 s = SharedPtrRef()
149 stats = ConstructorStats.get(A)
150 assert stats.alive() == 2
151
152 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
153 assert stats.alive() == 2
154 assert s.set_ref(ref)
155 with pytest.raises(RuntimeError) as excinfo:
156 assert s.set_holder(ref)
157 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
158
159 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
160 assert stats.alive() == 3
161 assert s.set_ref(copy)
162 assert s.set_holder(copy)
163
164 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
165 assert stats.alive() == 3
166 assert s.set_ref(holder_ref)
167 assert s.set_holder(holder_ref)
168
169 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
170 assert stats.alive() == 3
171 assert s.set_ref(holder_copy)
172 assert s.set_holder(holder_copy)
173
174 del ref, copy, holder_ref, holder_copy, s
175 assert stats.alive() == 0
176
177
178def test_shared_ptr_from_this_and_references():
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400179 from pybind11_tests.smart_ptr import SharedFromThisRef, B, SharedFromThisVirt
Dean Moldovanab90ec62016-12-07 02:36:44 +0100180
181 s = SharedFromThisRef()
182 stats = ConstructorStats.get(B)
183 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 Rhinelanderb8ac4382017-05-19 13:34:55 -0400215 z = SharedFromThisVirt.get()
216 y = SharedFromThisVirt.get()
217 assert y is z
218
Dean Moldovanec009a72017-01-31 17:05:44 +0100219
220def test_move_only_holder():
221 from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder
222
223 a = TypeWithMoveOnlyHolder.make()
224 stats = ConstructorStats.get(TypeWithMoveOnlyHolder)
225 assert stats.alive() == 1
226 del a
227 assert stats.alive() == 0
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100228
229
230def test_smart_ptr_from_default():
231 from pybind11_tests.smart_ptr import HeldByDefaultHolder
232
233 instance = HeldByDefaultHolder()
234 with pytest.raises(RuntimeError) as excinfo:
235 HeldByDefaultHolder.load_shared_ptr(instance)
236 assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200237
238
239def test_shared_ptr_gc():
240 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
241 from pybind11_tests.smart_ptr import ElementList, ElementA
242
243 el = ElementList()
244 for i in range(10):
245 el.add(ElementA(i))
246 pytest.gc_collect()
247 for i, v in enumerate(el.get()):
248 assert i == v.value()