blob: 0f2d85fce96751802378b0e9f3f47b1724024f0c [file] [log] [blame]
Henry Schreinerd8c7ee02020-07-20 13:35:21 -04001# -*- coding: utf-8 -*-
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002import pytest
Dean Moldovan0bc272b2017-06-22 23:42:11 +02003
4from pybind11_tests import virtual_functions as m
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02005from pybind11_tests import ConstructorStats
6
7
8def test_override(capture, msg):
Dean Moldovan0bc272b2017-06-22 23:42:11 +02009 class ExtendedExampleVirt(m.ExampleVirt):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020010 def __init__(self, state):
11 super(ExtendedExampleVirt, self).__init__(state + 1)
12 self.data = "Hello world"
13
14 def run(self, value):
15 print('ExtendedExampleVirt::run(%i), calling parent..' % value)
16 return super(ExtendedExampleVirt, self).run(value + 1)
17
18 def run_bool(self):
19 print('ExtendedExampleVirt::run_bool()')
20 return False
21
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040022 def get_string1(self):
23 return "override1"
24
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020025 def pure_virtual(self):
26 print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
27
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040028 class ExtendedExampleVirt2(ExtendedExampleVirt):
29 def __init__(self, state):
30 super(ExtendedExampleVirt2, self).__init__(state + 1)
31
32 def get_string2(self):
33 return "override2"
34
Dean Moldovan0bc272b2017-06-22 23:42:11 +020035 ex12 = m.ExampleVirt(10)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020036 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020037 assert m.runExampleVirt(ex12, 20) == 30
Dean Moldovan76e993a2016-12-13 00:59:28 +010038 assert capture == """
39 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
40 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020041
42 with pytest.raises(RuntimeError) as excinfo:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020043 m.runExampleVirtVirtual(ex12)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020044 assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
45
46 ex12p = ExtendedExampleVirt(10)
47 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020048 assert m.runExampleVirt(ex12p, 20) == 32
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020049 assert capture == """
50 ExtendedExampleVirt::run(20), calling parent..
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040051 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010052 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020053 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020054 assert m.runExampleVirtBool(ex12p) is False
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020055 assert capture == "ExtendedExampleVirt::run_bool()"
56 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020057 m.runExampleVirtVirtual(ex12p)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020058 assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
59
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040060 ex12p2 = ExtendedExampleVirt2(15)
61 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020062 assert m.runExampleVirt(ex12p2, 50) == 68
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040063 assert capture == """
64 ExtendedExampleVirt::run(50), calling parent..
65 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010066 """ # noqa: E501 line too long
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040067
Dean Moldovan0bc272b2017-06-22 23:42:11 +020068 cstats = ConstructorStats.get(m.ExampleVirt)
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040069 assert cstats.alive() == 3
70 del ex12, ex12p, ex12p2
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020071 assert cstats.alive() == 0
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040072 assert cstats.values() == ['10', '11', '17']
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020073 assert cstats.copy_constructions == 0
74 assert cstats.move_constructions >= 0
75
76
Dean Moldovan0bc272b2017-06-22 23:42:11 +020077def test_alias_delay_initialization1(capture):
78 """`A` only initializes its trampoline class when we inherit from it
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020079
Dean Moldovan0bc272b2017-06-22 23:42:11 +020080 If we just create and use an A instance directly, the trampoline initialization is
81 bypassed and we only initialize an A() instead (for performance reasons).
82 """
83 class B(m.A):
84 def __init__(self):
85 super(B, self).__init__()
86
87 def f(self):
88 print("In python f()")
89
90 # C++ version
91 with capture:
92 a = m.A()
93 m.call_f(a)
94 del a
95 pytest.gc_collect()
96 assert capture == "A.f()"
97
98 # Python version
99 with capture:
100 b = B()
101 m.call_f(b)
102 del b
103 pytest.gc_collect()
104 assert capture == """
105 PyA.PyA()
106 PyA.f()
107 In python f()
108 PyA.~PyA()
109 """
110
111
112def test_alias_delay_initialization2(capture):
113 """`A2`, unlike the above, is configured to always initialize the alias
114
115 While the extra initialization and extra class layer has small virtual dispatch
116 performance penalty, it also allows us to do more things with the trampoline
117 class such as defining local variables and performing construction/destruction.
118 """
119 class B2(m.A2):
120 def __init__(self):
121 super(B2, self).__init__()
122
123 def f(self):
124 print("In python B2.f()")
125
126 # No python subclass version
127 with capture:
128 a2 = m.A2()
129 m.call_f(a2)
130 del a2
131 pytest.gc_collect()
Jason Rhinelander464d9892017-06-12 21:52:48 -0400132 a3 = m.A2(1)
133 m.call_f(a3)
134 del a3
135 pytest.gc_collect()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200136 assert capture == """
137 PyA2.PyA2()
138 PyA2.f()
139 A2.f()
140 PyA2.~PyA2()
Jason Rhinelander464d9892017-06-12 21:52:48 -0400141 PyA2.PyA2()
142 PyA2.f()
143 A2.f()
144 PyA2.~PyA2()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200145 """
146
147 # Python subclass version
148 with capture:
149 b2 = B2()
150 m.call_f(b2)
151 del b2
152 pytest.gc_collect()
153 assert capture == """
154 PyA2.PyA2()
155 PyA2.f()
156 In python B2.f()
157 PyA2.~PyA2()
158 """
159
160
Jason Rhinelander391c7542017-07-25 16:47:36 -0400161# PyPy: Reference count > 1 causes call with noncopyable instance
162# to fail in ncv1.print_nc()
163@pytest.unsupported_on_pypy
164@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
165def test_move_support():
166 class NCVirtExt(m.NCVirt):
167 def get_noncopyable(self, a, b):
168 # Constructs and returns a new instance:
169 nc = m.NonCopyable(a * a, b * b)
170 return nc
171
172 def get_movable(self, a, b):
173 # Return a referenced copy
174 self.movable = m.Movable(a, b)
175 return self.movable
176
177 class NCVirtExt2(m.NCVirt):
178 def get_noncopyable(self, a, b):
179 # Keep a reference: this is going to throw an exception
180 self.nc = m.NonCopyable(a, b)
181 return self.nc
182
183 def get_movable(self, a, b):
184 # Return a new instance without storing it
185 return m.Movable(a, b)
186
187 ncv1 = NCVirtExt()
188 assert ncv1.print_nc(2, 3) == "36"
189 assert ncv1.print_movable(4, 5) == "9"
190 ncv2 = NCVirtExt2()
191 assert ncv2.print_movable(7, 7) == "14"
192 # Don't check the exception message here because it differs under debug/non-debug mode
193 with pytest.raises(RuntimeError):
194 ncv2.print_nc(9, 9)
195
196 nc_stats = ConstructorStats.get(m.NonCopyable)
197 mv_stats = ConstructorStats.get(m.Movable)
198 assert nc_stats.alive() == 1
199 assert mv_stats.alive() == 1
200 del ncv1, ncv2
201 assert nc_stats.alive() == 0
202 assert mv_stats.alive() == 0
203 assert nc_stats.values() == ['4', '9', '9', '9']
204 assert mv_stats.values() == ['4', '5', '7', '7']
205 assert nc_stats.copy_constructions == 0
206 assert mv_stats.copy_constructions == 1
207 assert nc_stats.move_constructions >= 0
208 assert mv_stats.move_constructions >= 0
209
210
211def test_dispatch_issue(msg):
212 """#159: virtual function dispatch has problems with similar-named functions"""
213 class PyClass1(m.DispatchIssue):
214 def dispatch(self):
215 return "Yay.."
216
217 class PyClass2(m.DispatchIssue):
218 def dispatch(self):
219 with pytest.raises(RuntimeError) as excinfo:
220 super(PyClass2, self).dispatch()
221 assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
222
223 p = PyClass1()
224 return m.dispatch_issue_go(p)
225
226 b = PyClass2()
227 assert m.dispatch_issue_go(b) == "Yay.."
228
229
230def test_override_ref():
Unknown0b3f44e2017-11-01 21:08:06 -0400231 """#392/397: overriding reference-returning functions"""
Jason Rhinelander391c7542017-07-25 16:47:36 -0400232 o = m.OverrideTest("asdf")
233
234 # Not allowed (see associated .cpp comment)
235 # i = o.str_ref()
236 # assert o.str_ref() == "asdf"
237 assert o.str_value() == "asdf"
238
239 assert o.A_value().value == "hi"
240 a = o.A_ref()
241 assert a.value == "hi"
242 a.value = "bye"
243 assert a.value == "bye"
244
245
246def test_inherited_virtuals():
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200247 class AR(m.A_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200248 def unlucky_number(self):
249 return 99
250
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200251 class AT(m.A_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200252 def unlucky_number(self):
253 return 999
254
Dean Moldovanbad17402016-11-20 21:21:54 +0100255 obj = AR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200256 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200257 assert obj.unlucky_number() == 99
Jason Rhinelander20978262016-08-29 18:16:46 -0400258 assert obj.say_everything() == "hi 99"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200259
Dean Moldovanbad17402016-11-20 21:21:54 +0100260 obj = AT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200261 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200262 assert obj.unlucky_number() == 999
Jason Rhinelander20978262016-08-29 18:16:46 -0400263 assert obj.say_everything() == "hi 999"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200264
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200265 for obj in [m.B_Repeat(), m.B_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200266 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200267 assert obj.unlucky_number() == 13
268 assert obj.lucky_number() == 7.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400269 assert obj.say_everything() == "B says hi 1 times 13"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200270
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200271 for obj in [m.C_Repeat(), m.C_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200272 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200273 assert obj.unlucky_number() == 4444
274 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400275 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200276
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200277 class CR(m.C_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200278 def lucky_number(self):
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200279 return m.C_Repeat.lucky_number(self) + 1.25
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200280
Dean Moldovanbad17402016-11-20 21:21:54 +0100281 obj = CR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200282 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200283 assert obj.unlucky_number() == 4444
284 assert obj.lucky_number() == 889.25
Jason Rhinelander20978262016-08-29 18:16:46 -0400285 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200286
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200287 class CT(m.C_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200288 pass
289
Dean Moldovanbad17402016-11-20 21:21:54 +0100290 obj = CT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200291 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200292 assert obj.unlucky_number() == 4444
293 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400294 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200295
Dean Moldovanbad17402016-11-20 21:21:54 +0100296 class CCR(CR):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200297 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100298 return CR.lucky_number(self) * 10
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200299
Dean Moldovanbad17402016-11-20 21:21:54 +0100300 obj = CCR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200301 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200302 assert obj.unlucky_number() == 4444
303 assert obj.lucky_number() == 8892.5
Jason Rhinelander20978262016-08-29 18:16:46 -0400304 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200305
Dean Moldovanbad17402016-11-20 21:21:54 +0100306 class CCT(CT):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200307 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100308 return CT.lucky_number(self) * 1000
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200309
Dean Moldovanbad17402016-11-20 21:21:54 +0100310 obj = CCT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200311 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200312 assert obj.unlucky_number() == 4444
313 assert obj.lucky_number() == 888000.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400314 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200315
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200316 class DR(m.D_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200317 def unlucky_number(self):
318 return 123
319
320 def lucky_number(self):
321 return 42.0
322
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200323 for obj in [m.D_Repeat(), m.D_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200324 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200325 assert obj.unlucky_number() == 4444
326 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400327 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200328
Dean Moldovanbad17402016-11-20 21:21:54 +0100329 obj = DR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200330 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200331 assert obj.unlucky_number() == 123
332 assert obj.lucky_number() == 42.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400333 assert obj.say_everything() == "B says hi 1 times 123"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200334
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200335 class DT(m.D_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200336 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100337 return "DT says:" + (' quack' * times)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200338
339 def unlucky_number(self):
340 return 1234
341
342 def lucky_number(self):
343 return -4.25
344
Dean Moldovanbad17402016-11-20 21:21:54 +0100345 obj = DT()
346 assert obj.say_something(3) == "DT says: quack quack quack"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200347 assert obj.unlucky_number() == 1234
348 assert obj.lucky_number() == -4.25
Dean Moldovanbad17402016-11-20 21:21:54 +0100349 assert obj.say_everything() == "DT says: quack 1234"
Jason Rhinelander20978262016-08-29 18:16:46 -0400350
Dean Moldovanbad17402016-11-20 21:21:54 +0100351 class DT2(DT):
Jason Rhinelander20978262016-08-29 18:16:46 -0400352 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100353 return "DT2: " + ('QUACK' * times)
Jason Rhinelander20978262016-08-29 18:16:46 -0400354
355 def unlucky_number(self):
356 return -3
357
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200358 class BT(m.B_Tpl):
Jason Rhinelander20978262016-08-29 18:16:46 -0400359 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100360 return "BT" * times
361
Jason Rhinelander20978262016-08-29 18:16:46 -0400362 def unlucky_number(self):
363 return -7
Dean Moldovanbad17402016-11-20 21:21:54 +0100364
Jason Rhinelander20978262016-08-29 18:16:46 -0400365 def lucky_number(self):
366 return -1.375
367
Dean Moldovanbad17402016-11-20 21:21:54 +0100368 obj = BT()
369 assert obj.say_something(3) == "BTBTBT"
Jason Rhinelander20978262016-08-29 18:16:46 -0400370 assert obj.unlucky_number() == -7
371 assert obj.lucky_number() == -1.375
Dean Moldovanbad17402016-11-20 21:21:54 +0100372 assert obj.say_everything() == "BT -7"
Wenzel Jakob44e39e02018-09-11 09:32:45 +0200373
374
375def test_issue_1454():
376 # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
377 m.test_gil()
378 m.test_gil_from_thread()