blob: 4b1e20ea4296c2041e9b30de5a0dd875bdde4e39 [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
135def test_shared_ptr_and_references():
136 from pybind11_tests.smart_ptr import SharedPtrRef, A
137
138 s = SharedPtrRef()
139 stats = ConstructorStats.get(A)
140 assert stats.alive() == 2
141
142 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
143 assert stats.alive() == 2
144 assert s.set_ref(ref)
145 with pytest.raises(RuntimeError) as excinfo:
146 assert s.set_holder(ref)
147 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
148
149 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
150 assert stats.alive() == 3
151 assert s.set_ref(copy)
152 assert s.set_holder(copy)
153
154 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
155 assert stats.alive() == 3
156 assert s.set_ref(holder_ref)
157 assert s.set_holder(holder_ref)
158
159 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
160 assert stats.alive() == 3
161 assert s.set_ref(holder_copy)
162 assert s.set_holder(holder_copy)
163
164 del ref, copy, holder_ref, holder_copy, s
165 assert stats.alive() == 0
166
167
168def test_shared_ptr_from_this_and_references():
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400169 from pybind11_tests.smart_ptr import SharedFromThisRef, B, SharedFromThisVirt
Dean Moldovanab90ec62016-12-07 02:36:44 +0100170
171 s = SharedFromThisRef()
172 stats = ConstructorStats.get(B)
173 assert stats.alive() == 2
174
175 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
176 assert stats.alive() == 2
177 assert s.set_ref(ref)
178 assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
179
180 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
181 assert stats.alive() == 2
182 assert s.set_ref(bad_wp)
183 with pytest.raises(RuntimeError) as excinfo:
184 assert s.set_holder(bad_wp)
185 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
186
187 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
188 assert stats.alive() == 3
189 assert s.set_ref(copy)
190 assert s.set_holder(copy)
191
192 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
193 assert stats.alive() == 3
194 assert s.set_ref(holder_ref)
195 assert s.set_holder(holder_ref)
196
197 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
198 assert stats.alive() == 3
199 assert s.set_ref(holder_copy)
200 assert s.set_holder(holder_copy)
201
202 del ref, bad_wp, copy, holder_ref, holder_copy, s
203 assert stats.alive() == 0
Dean Moldovanec009a72017-01-31 17:05:44 +0100204
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400205 z = SharedFromThisVirt.get()
206 y = SharedFromThisVirt.get()
207 assert y is z
208
Dean Moldovanec009a72017-01-31 17:05:44 +0100209
210def test_move_only_holder():
211 from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder
212
213 a = TypeWithMoveOnlyHolder.make()
214 stats = ConstructorStats.get(TypeWithMoveOnlyHolder)
215 assert stats.alive() == 1
216 del a
217 assert stats.alive() == 0
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100218
219
220def test_smart_ptr_from_default():
221 from pybind11_tests.smart_ptr import HeldByDefaultHolder
222
223 instance = HeldByDefaultHolder()
224 with pytest.raises(RuntimeError) as excinfo:
225 HeldByDefaultHolder.load_shared_ptr(instance)
226 assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)