blob: 4dfe0036fc232032176a52c08bf4815d9d4b2b57 [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
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500118def test_large_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400119 o = m.MyObject5(5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500120 assert o.value == 5
Jason Rhinelander391c7542017-07-25 16:47:36 -0400121 cstats = ConstructorStats.get(m.MyObject5)
Jason Rhinelandere45c2112017-02-22 21:36:09 -0500122 assert cstats.alive() == 1
123 del o
124 assert cstats.alive() == 0
125
126
Dean Moldovanab90ec62016-12-07 02:36:44 +0100127def test_shared_ptr_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400128 s = m.SharedPtrRef()
129 stats = ConstructorStats.get(m.A)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100130 assert stats.alive() == 2
131
132 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
133 assert stats.alive() == 2
134 assert s.set_ref(ref)
135 with pytest.raises(RuntimeError) as excinfo:
136 assert s.set_holder(ref)
137 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
138
139 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
140 assert stats.alive() == 3
141 assert s.set_ref(copy)
142 assert s.set_holder(copy)
143
144 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
145 assert stats.alive() == 3
146 assert s.set_ref(holder_ref)
147 assert s.set_holder(holder_ref)
148
149 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
150 assert stats.alive() == 3
151 assert s.set_ref(holder_copy)
152 assert s.set_holder(holder_copy)
153
154 del ref, copy, holder_ref, holder_copy, s
155 assert stats.alive() == 0
156
157
158def test_shared_ptr_from_this_and_references():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400159 s = m.SharedFromThisRef()
160 stats = ConstructorStats.get(m.B)
Dean Moldovanab90ec62016-12-07 02:36:44 +0100161 assert stats.alive() == 2
162
163 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
164 assert stats.alive() == 2
165 assert s.set_ref(ref)
166 assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference
167
168 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
169 assert stats.alive() == 2
170 assert s.set_ref(bad_wp)
171 with pytest.raises(RuntimeError) as excinfo:
172 assert s.set_holder(bad_wp)
173 assert "Unable to cast from non-held to held instance" in str(excinfo.value)
174
175 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
176 assert stats.alive() == 3
177 assert s.set_ref(copy)
178 assert s.set_holder(copy)
179
180 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
181 assert stats.alive() == 3
182 assert s.set_ref(holder_ref)
183 assert s.set_holder(holder_ref)
184
185 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
186 assert stats.alive() == 3
187 assert s.set_ref(holder_copy)
188 assert s.set_holder(holder_copy)
189
190 del ref, bad_wp, copy, holder_ref, holder_copy, s
191 assert stats.alive() == 0
Dean Moldovanec009a72017-01-31 17:05:44 +0100192
Jason Rhinelander391c7542017-07-25 16:47:36 -0400193 z = m.SharedFromThisVirt.get()
194 y = m.SharedFromThisVirt.get()
Jason Rhinelanderb8ac4382017-05-19 13:34:55 -0400195 assert y is z
196
Dean Moldovanec009a72017-01-31 17:05:44 +0100197
198def test_move_only_holder():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400199 a = m.TypeWithMoveOnlyHolder.make()
200 stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
Dean Moldovanec009a72017-01-31 17:05:44 +0100201 assert stats.alive() == 1
202 del a
203 assert stats.alive() == 0
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100204
205
206def test_smart_ptr_from_default():
Jason Rhinelander391c7542017-07-25 16:47:36 -0400207 instance = m.HeldByDefaultHolder()
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100208 with pytest.raises(RuntimeError) as excinfo:
Jason Rhinelander391c7542017-07-25 16:47:36 -0400209 m.HeldByDefaultHolder.load_shared_ptr(instance)
Dean Moldovancd3d1fc2017-03-20 21:53:24 +0100210 assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo)
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200211
212
213def test_shared_ptr_gc():
214 """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
Jason Rhinelander391c7542017-07-25 16:47:36 -0400215 el = m.ElementList()
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200216 for i in range(10):
Jason Rhinelander391c7542017-07-25 16:47:36 -0400217 el.add(m.ElementA(i))
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200218 pytest.gc_collect()
219 for i, v in enumerate(el.get()):
220 assert i == v.value()