blob: 66a353ae7f3c5a81b1254bcc92f90a7aedab1c6d [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
Henry Schreiner4d9024e2020-08-16 16:02:12 -04004import env # noqa: F401
5
andriish38370a82020-09-12 04:06:52 +02006m = pytest.importorskip("pybind11_tests.virtual_functions")
7from pybind11_tests import ConstructorStats # noqa: E402
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02008
9
10def test_override(capture, msg):
Dean Moldovan0bc272b2017-06-22 23:42:11 +020011 class ExtendedExampleVirt(m.ExampleVirt):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020012 def __init__(self, state):
13 super(ExtendedExampleVirt, self).__init__(state + 1)
14 self.data = "Hello world"
15
16 def run(self, value):
17 print('ExtendedExampleVirt::run(%i), calling parent..' % value)
18 return super(ExtendedExampleVirt, self).run(value + 1)
19
20 def run_bool(self):
21 print('ExtendedExampleVirt::run_bool()')
22 return False
23
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040024 def get_string1(self):
25 return "override1"
26
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020027 def pure_virtual(self):
28 print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
29
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040030 class ExtendedExampleVirt2(ExtendedExampleVirt):
31 def __init__(self, state):
32 super(ExtendedExampleVirt2, self).__init__(state + 1)
33
34 def get_string2(self):
35 return "override2"
36
Dean Moldovan0bc272b2017-06-22 23:42:11 +020037 ex12 = m.ExampleVirt(10)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020038 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020039 assert m.runExampleVirt(ex12, 20) == 30
Dean Moldovan76e993a2016-12-13 00:59:28 +010040 assert capture == """
41 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
42 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020043
44 with pytest.raises(RuntimeError) as excinfo:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020045 m.runExampleVirtVirtual(ex12)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020046 assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
47
48 ex12p = ExtendedExampleVirt(10)
49 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020050 assert m.runExampleVirt(ex12p, 20) == 32
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020051 assert capture == """
52 ExtendedExampleVirt::run(20), calling parent..
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040053 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010054 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020055 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020056 assert m.runExampleVirtBool(ex12p) is False
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020057 assert capture == "ExtendedExampleVirt::run_bool()"
58 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020059 m.runExampleVirtVirtual(ex12p)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020060 assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
61
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040062 ex12p2 = ExtendedExampleVirt2(15)
63 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020064 assert m.runExampleVirt(ex12p2, 50) == 68
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040065 assert capture == """
66 ExtendedExampleVirt::run(50), calling parent..
67 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010068 """ # noqa: E501 line too long
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040069
Dean Moldovan0bc272b2017-06-22 23:42:11 +020070 cstats = ConstructorStats.get(m.ExampleVirt)
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040071 assert cstats.alive() == 3
72 del ex12, ex12p, ex12p2
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020073 assert cstats.alive() == 0
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040074 assert cstats.values() == ['10', '11', '17']
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020075 assert cstats.copy_constructions == 0
76 assert cstats.move_constructions >= 0
77
78
Dean Moldovan0bc272b2017-06-22 23:42:11 +020079def test_alias_delay_initialization1(capture):
80 """`A` only initializes its trampoline class when we inherit from it
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020081
Dean Moldovan0bc272b2017-06-22 23:42:11 +020082 If we just create and use an A instance directly, the trampoline initialization is
83 bypassed and we only initialize an A() instead (for performance reasons).
84 """
85 class B(m.A):
86 def __init__(self):
87 super(B, self).__init__()
88
89 def f(self):
90 print("In python f()")
91
92 # C++ version
93 with capture:
94 a = m.A()
95 m.call_f(a)
96 del a
97 pytest.gc_collect()
98 assert capture == "A.f()"
99
100 # Python version
101 with capture:
102 b = B()
103 m.call_f(b)
104 del b
105 pytest.gc_collect()
106 assert capture == """
107 PyA.PyA()
108 PyA.f()
109 In python f()
110 PyA.~PyA()
111 """
112
113
114def test_alias_delay_initialization2(capture):
115 """`A2`, unlike the above, is configured to always initialize the alias
116
117 While the extra initialization and extra class layer has small virtual dispatch
118 performance penalty, it also allows us to do more things with the trampoline
119 class such as defining local variables and performing construction/destruction.
120 """
121 class B2(m.A2):
122 def __init__(self):
123 super(B2, self).__init__()
124
125 def f(self):
126 print("In python B2.f()")
127
128 # No python subclass version
129 with capture:
130 a2 = m.A2()
131 m.call_f(a2)
132 del a2
133 pytest.gc_collect()
Jason Rhinelander464d9892017-06-12 21:52:48 -0400134 a3 = m.A2(1)
135 m.call_f(a3)
136 del a3
137 pytest.gc_collect()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200138 assert capture == """
139 PyA2.PyA2()
140 PyA2.f()
141 A2.f()
142 PyA2.~PyA2()
Jason Rhinelander464d9892017-06-12 21:52:48 -0400143 PyA2.PyA2()
144 PyA2.f()
145 A2.f()
146 PyA2.~PyA2()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200147 """
148
149 # Python subclass version
150 with capture:
151 b2 = B2()
152 m.call_f(b2)
153 del b2
154 pytest.gc_collect()
155 assert capture == """
156 PyA2.PyA2()
157 PyA2.f()
158 In python B2.f()
159 PyA2.~PyA2()
160 """
161
162
Jason Rhinelander391c7542017-07-25 16:47:36 -0400163# PyPy: Reference count > 1 causes call with noncopyable instance
164# to fail in ncv1.print_nc()
Henry Schreiner4d9024e2020-08-16 16:02:12 -0400165@pytest.mark.xfail("env.PYPY")
Jason Rhinelander391c7542017-07-25 16:47:36 -0400166@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
167def test_move_support():
168 class NCVirtExt(m.NCVirt):
169 def get_noncopyable(self, a, b):
170 # Constructs and returns a new instance:
171 nc = m.NonCopyable(a * a, b * b)
172 return nc
173
174 def get_movable(self, a, b):
175 # Return a referenced copy
176 self.movable = m.Movable(a, b)
177 return self.movable
178
179 class NCVirtExt2(m.NCVirt):
180 def get_noncopyable(self, a, b):
181 # Keep a reference: this is going to throw an exception
182 self.nc = m.NonCopyable(a, b)
183 return self.nc
184
185 def get_movable(self, a, b):
186 # Return a new instance without storing it
187 return m.Movable(a, b)
188
189 ncv1 = NCVirtExt()
190 assert ncv1.print_nc(2, 3) == "36"
191 assert ncv1.print_movable(4, 5) == "9"
192 ncv2 = NCVirtExt2()
193 assert ncv2.print_movable(7, 7) == "14"
194 # Don't check the exception message here because it differs under debug/non-debug mode
195 with pytest.raises(RuntimeError):
196 ncv2.print_nc(9, 9)
197
198 nc_stats = ConstructorStats.get(m.NonCopyable)
199 mv_stats = ConstructorStats.get(m.Movable)
200 assert nc_stats.alive() == 1
201 assert mv_stats.alive() == 1
202 del ncv1, ncv2
203 assert nc_stats.alive() == 0
204 assert mv_stats.alive() == 0
205 assert nc_stats.values() == ['4', '9', '9', '9']
206 assert mv_stats.values() == ['4', '5', '7', '7']
207 assert nc_stats.copy_constructions == 0
208 assert mv_stats.copy_constructions == 1
209 assert nc_stats.move_constructions >= 0
210 assert mv_stats.move_constructions >= 0
211
212
213def test_dispatch_issue(msg):
214 """#159: virtual function dispatch has problems with similar-named functions"""
215 class PyClass1(m.DispatchIssue):
216 def dispatch(self):
217 return "Yay.."
218
219 class PyClass2(m.DispatchIssue):
220 def dispatch(self):
221 with pytest.raises(RuntimeError) as excinfo:
222 super(PyClass2, self).dispatch()
223 assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
224
225 p = PyClass1()
226 return m.dispatch_issue_go(p)
227
228 b = PyClass2()
229 assert m.dispatch_issue_go(b) == "Yay.."
230
231
232def test_override_ref():
Unknown0b3f44e2017-11-01 21:08:06 -0400233 """#392/397: overriding reference-returning functions"""
Jason Rhinelander391c7542017-07-25 16:47:36 -0400234 o = m.OverrideTest("asdf")
235
236 # Not allowed (see associated .cpp comment)
237 # i = o.str_ref()
238 # assert o.str_ref() == "asdf"
239 assert o.str_value() == "asdf"
240
241 assert o.A_value().value == "hi"
242 a = o.A_ref()
243 assert a.value == "hi"
244 a.value = "bye"
245 assert a.value == "bye"
246
247
248def test_inherited_virtuals():
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200249 class AR(m.A_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200250 def unlucky_number(self):
251 return 99
252
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200253 class AT(m.A_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200254 def unlucky_number(self):
255 return 999
256
Dean Moldovanbad17402016-11-20 21:21:54 +0100257 obj = AR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200258 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200259 assert obj.unlucky_number() == 99
Jason Rhinelander20978262016-08-29 18:16:46 -0400260 assert obj.say_everything() == "hi 99"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200261
Dean Moldovanbad17402016-11-20 21:21:54 +0100262 obj = AT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200263 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200264 assert obj.unlucky_number() == 999
Jason Rhinelander20978262016-08-29 18:16:46 -0400265 assert obj.say_everything() == "hi 999"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200266
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200267 for obj in [m.B_Repeat(), m.B_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200268 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200269 assert obj.unlucky_number() == 13
270 assert obj.lucky_number() == 7.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400271 assert obj.say_everything() == "B says hi 1 times 13"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200272
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200273 for obj in [m.C_Repeat(), m.C_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200274 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200275 assert obj.unlucky_number() == 4444
276 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400277 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200278
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200279 class CR(m.C_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200280 def lucky_number(self):
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200281 return m.C_Repeat.lucky_number(self) + 1.25
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200282
Dean Moldovanbad17402016-11-20 21:21:54 +0100283 obj = CR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200284 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200285 assert obj.unlucky_number() == 4444
286 assert obj.lucky_number() == 889.25
Jason Rhinelander20978262016-08-29 18:16:46 -0400287 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200288
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200289 class CT(m.C_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200290 pass
291
Dean Moldovanbad17402016-11-20 21:21:54 +0100292 obj = CT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200293 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200294 assert obj.unlucky_number() == 4444
295 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400296 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200297
Dean Moldovanbad17402016-11-20 21:21:54 +0100298 class CCR(CR):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200299 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100300 return CR.lucky_number(self) * 10
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200301
Dean Moldovanbad17402016-11-20 21:21:54 +0100302 obj = CCR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200303 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200304 assert obj.unlucky_number() == 4444
305 assert obj.lucky_number() == 8892.5
Jason Rhinelander20978262016-08-29 18:16:46 -0400306 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200307
Dean Moldovanbad17402016-11-20 21:21:54 +0100308 class CCT(CT):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200309 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100310 return CT.lucky_number(self) * 1000
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200311
Dean Moldovanbad17402016-11-20 21:21:54 +0100312 obj = CCT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200313 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200314 assert obj.unlucky_number() == 4444
315 assert obj.lucky_number() == 888000.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400316 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200317
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200318 class DR(m.D_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200319 def unlucky_number(self):
320 return 123
321
322 def lucky_number(self):
323 return 42.0
324
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200325 for obj in [m.D_Repeat(), m.D_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200326 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200327 assert obj.unlucky_number() == 4444
328 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400329 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200330
Dean Moldovanbad17402016-11-20 21:21:54 +0100331 obj = DR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200332 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200333 assert obj.unlucky_number() == 123
334 assert obj.lucky_number() == 42.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400335 assert obj.say_everything() == "B says hi 1 times 123"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200336
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200337 class DT(m.D_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200338 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100339 return "DT says:" + (' quack' * times)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200340
341 def unlucky_number(self):
342 return 1234
343
344 def lucky_number(self):
345 return -4.25
346
Dean Moldovanbad17402016-11-20 21:21:54 +0100347 obj = DT()
348 assert obj.say_something(3) == "DT says: quack quack quack"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200349 assert obj.unlucky_number() == 1234
350 assert obj.lucky_number() == -4.25
Dean Moldovanbad17402016-11-20 21:21:54 +0100351 assert obj.say_everything() == "DT says: quack 1234"
Jason Rhinelander20978262016-08-29 18:16:46 -0400352
Dean Moldovanbad17402016-11-20 21:21:54 +0100353 class DT2(DT):
Jason Rhinelander20978262016-08-29 18:16:46 -0400354 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100355 return "DT2: " + ('QUACK' * times)
Jason Rhinelander20978262016-08-29 18:16:46 -0400356
357 def unlucky_number(self):
358 return -3
359
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200360 class BT(m.B_Tpl):
Jason Rhinelander20978262016-08-29 18:16:46 -0400361 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100362 return "BT" * times
363
Jason Rhinelander20978262016-08-29 18:16:46 -0400364 def unlucky_number(self):
365 return -7
Dean Moldovanbad17402016-11-20 21:21:54 +0100366
Jason Rhinelander20978262016-08-29 18:16:46 -0400367 def lucky_number(self):
368 return -1.375
369
Dean Moldovanbad17402016-11-20 21:21:54 +0100370 obj = BT()
371 assert obj.say_something(3) == "BTBTBT"
Jason Rhinelander20978262016-08-29 18:16:46 -0400372 assert obj.unlucky_number() == -7
373 assert obj.lucky_number() == -1.375
Dean Moldovanbad17402016-11-20 21:21:54 +0100374 assert obj.say_everything() == "BT -7"
Wenzel Jakob44e39e02018-09-11 09:32:45 +0200375
376
377def test_issue_1454():
378 # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
379 m.test_gil()
380 m.test_gil_from_thread()