blob: 7d1698dab0f4b0e3acee5f30f8e68da42152d135 [file] [log] [blame]
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02001import pytest
Dean Moldovan0bc272b2017-06-22 23:42:11 +02002
3from pybind11_tests import virtual_functions as m
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02004from pybind11_tests import ConstructorStats
5
6
7def test_override(capture, msg):
Dean Moldovan0bc272b2017-06-22 23:42:11 +02008 class ExtendedExampleVirt(m.ExampleVirt):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02009 def __init__(self, state):
10 super(ExtendedExampleVirt, self).__init__(state + 1)
11 self.data = "Hello world"
12
13 def run(self, value):
14 print('ExtendedExampleVirt::run(%i), calling parent..' % value)
15 return super(ExtendedExampleVirt, self).run(value + 1)
16
17 def run_bool(self):
18 print('ExtendedExampleVirt::run_bool()')
19 return False
20
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040021 def get_string1(self):
22 return "override1"
23
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020024 def pure_virtual(self):
25 print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
26
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040027 class ExtendedExampleVirt2(ExtendedExampleVirt):
28 def __init__(self, state):
29 super(ExtendedExampleVirt2, self).__init__(state + 1)
30
31 def get_string2(self):
32 return "override2"
33
Dean Moldovan0bc272b2017-06-22 23:42:11 +020034 ex12 = m.ExampleVirt(10)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020035 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020036 assert m.runExampleVirt(ex12, 20) == 30
Dean Moldovan76e993a2016-12-13 00:59:28 +010037 assert capture == """
38 Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)
39 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020040
41 with pytest.raises(RuntimeError) as excinfo:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020042 m.runExampleVirtVirtual(ex12)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020043 assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
44
45 ex12p = ExtendedExampleVirt(10)
46 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020047 assert m.runExampleVirt(ex12p, 20) == 32
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020048 assert capture == """
49 ExtendedExampleVirt::run(20), calling parent..
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040050 Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010051 """ # noqa: E501 line too long
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020052 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020053 assert m.runExampleVirtBool(ex12p) is False
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020054 assert capture == "ExtendedExampleVirt::run_bool()"
55 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020056 m.runExampleVirtVirtual(ex12p)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020057 assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
58
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040059 ex12p2 = ExtendedExampleVirt2(15)
60 with capture:
Dean Moldovan0bc272b2017-06-22 23:42:11 +020061 assert m.runExampleVirt(ex12p2, 50) == 68
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040062 assert capture == """
63 ExtendedExampleVirt::run(50), calling parent..
64 Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2)
Dean Moldovan76e993a2016-12-13 00:59:28 +010065 """ # noqa: E501 line too long
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040066
Dean Moldovan0bc272b2017-06-22 23:42:11 +020067 cstats = ConstructorStats.get(m.ExampleVirt)
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040068 assert cstats.alive() == 3
69 del ex12, ex12p, ex12p2
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020070 assert cstats.alive() == 0
Jason Rhinelander7dfb9322016-09-08 14:49:43 -040071 assert cstats.values() == ['10', '11', '17']
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020072 assert cstats.copy_constructions == 0
73 assert cstats.move_constructions >= 0
74
75
Dean Moldovan0bc272b2017-06-22 23:42:11 +020076def test_alias_delay_initialization1(capture):
77 """`A` only initializes its trampoline class when we inherit from it
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020078
Dean Moldovan0bc272b2017-06-22 23:42:11 +020079 If we just create and use an A instance directly, the trampoline initialization is
80 bypassed and we only initialize an A() instead (for performance reasons).
81 """
82 class B(m.A):
83 def __init__(self):
84 super(B, self).__init__()
85
86 def f(self):
87 print("In python f()")
88
89 # C++ version
90 with capture:
91 a = m.A()
92 m.call_f(a)
93 del a
94 pytest.gc_collect()
95 assert capture == "A.f()"
96
97 # Python version
98 with capture:
99 b = B()
100 m.call_f(b)
101 del b
102 pytest.gc_collect()
103 assert capture == """
104 PyA.PyA()
105 PyA.f()
106 In python f()
107 PyA.~PyA()
108 """
109
110
111def test_alias_delay_initialization2(capture):
112 """`A2`, unlike the above, is configured to always initialize the alias
113
114 While the extra initialization and extra class layer has small virtual dispatch
115 performance penalty, it also allows us to do more things with the trampoline
116 class such as defining local variables and performing construction/destruction.
117 """
118 class B2(m.A2):
119 def __init__(self):
120 super(B2, self).__init__()
121
122 def f(self):
123 print("In python B2.f()")
124
125 # No python subclass version
126 with capture:
127 a2 = m.A2()
128 m.call_f(a2)
129 del a2
130 pytest.gc_collect()
131 assert capture == """
132 PyA2.PyA2()
133 PyA2.f()
134 A2.f()
135 PyA2.~PyA2()
136 """
137
138 # Python subclass version
139 with capture:
140 b2 = B2()
141 m.call_f(b2)
142 del b2
143 pytest.gc_collect()
144 assert capture == """
145 PyA2.PyA2()
146 PyA2.f()
147 In python B2.f()
148 PyA2.~PyA2()
149 """
150
151
152def test_inheriting_repeat():
153 class AR(m.A_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200154 def unlucky_number(self):
155 return 99
156
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200157 class AT(m.A_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200158 def unlucky_number(self):
159 return 999
160
Dean Moldovanbad17402016-11-20 21:21:54 +0100161 obj = AR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200162 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200163 assert obj.unlucky_number() == 99
Jason Rhinelander20978262016-08-29 18:16:46 -0400164 assert obj.say_everything() == "hi 99"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200165
Dean Moldovanbad17402016-11-20 21:21:54 +0100166 obj = AT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200167 assert obj.say_something(3) == "hihihi"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200168 assert obj.unlucky_number() == 999
Jason Rhinelander20978262016-08-29 18:16:46 -0400169 assert obj.say_everything() == "hi 999"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200170
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200171 for obj in [m.B_Repeat(), m.B_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200172 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200173 assert obj.unlucky_number() == 13
174 assert obj.lucky_number() == 7.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400175 assert obj.say_everything() == "B says hi 1 times 13"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200176
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200177 for obj in [m.C_Repeat(), m.C_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200178 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200179 assert obj.unlucky_number() == 4444
180 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400181 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200182
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200183 class CR(m.C_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200184 def lucky_number(self):
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200185 return m.C_Repeat.lucky_number(self) + 1.25
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200186
Dean Moldovanbad17402016-11-20 21:21:54 +0100187 obj = CR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200188 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200189 assert obj.unlucky_number() == 4444
190 assert obj.lucky_number() == 889.25
Jason Rhinelander20978262016-08-29 18:16:46 -0400191 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200192
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200193 class CT(m.C_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200194 pass
195
Dean Moldovanbad17402016-11-20 21:21:54 +0100196 obj = CT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200197 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200198 assert obj.unlucky_number() == 4444
199 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400200 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200201
Dean Moldovanbad17402016-11-20 21:21:54 +0100202 class CCR(CR):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200203 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100204 return CR.lucky_number(self) * 10
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200205
Dean Moldovanbad17402016-11-20 21:21:54 +0100206 obj = CCR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200207 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200208 assert obj.unlucky_number() == 4444
209 assert obj.lucky_number() == 8892.5
Jason Rhinelander20978262016-08-29 18:16:46 -0400210 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200211
Dean Moldovanbad17402016-11-20 21:21:54 +0100212 class CCT(CT):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200213 def lucky_number(self):
Dean Moldovanbad17402016-11-20 21:21:54 +0100214 return CT.lucky_number(self) * 1000
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200215
Dean Moldovanbad17402016-11-20 21:21:54 +0100216 obj = CCT()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200217 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200218 assert obj.unlucky_number() == 4444
219 assert obj.lucky_number() == 888000.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400220 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200221
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200222 class DR(m.D_Repeat):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200223 def unlucky_number(self):
224 return 123
225
226 def lucky_number(self):
227 return 42.0
228
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200229 for obj in [m.D_Repeat(), m.D_Tpl()]:
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200230 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200231 assert obj.unlucky_number() == 4444
232 assert obj.lucky_number() == 888.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400233 assert obj.say_everything() == "B says hi 1 times 4444"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200234
Dean Moldovanbad17402016-11-20 21:21:54 +0100235 obj = DR()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200236 assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200237 assert obj.unlucky_number() == 123
238 assert obj.lucky_number() == 42.0
Jason Rhinelander20978262016-08-29 18:16:46 -0400239 assert obj.say_everything() == "B says hi 1 times 123"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200240
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200241 class DT(m.D_Tpl):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200242 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100243 return "DT says:" + (' quack' * times)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200244
245 def unlucky_number(self):
246 return 1234
247
248 def lucky_number(self):
249 return -4.25
250
Dean Moldovanbad17402016-11-20 21:21:54 +0100251 obj = DT()
252 assert obj.say_something(3) == "DT says: quack quack quack"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200253 assert obj.unlucky_number() == 1234
254 assert obj.lucky_number() == -4.25
Dean Moldovanbad17402016-11-20 21:21:54 +0100255 assert obj.say_everything() == "DT says: quack 1234"
Jason Rhinelander20978262016-08-29 18:16:46 -0400256
Dean Moldovanbad17402016-11-20 21:21:54 +0100257 class DT2(DT):
Jason Rhinelander20978262016-08-29 18:16:46 -0400258 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100259 return "DT2: " + ('QUACK' * times)
Jason Rhinelander20978262016-08-29 18:16:46 -0400260
261 def unlucky_number(self):
262 return -3
263
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200264 class BT(m.B_Tpl):
Jason Rhinelander20978262016-08-29 18:16:46 -0400265 def say_something(self, times):
Dean Moldovanbad17402016-11-20 21:21:54 +0100266 return "BT" * times
267
Jason Rhinelander20978262016-08-29 18:16:46 -0400268 def unlucky_number(self):
269 return -7
Dean Moldovanbad17402016-11-20 21:21:54 +0100270
Jason Rhinelander20978262016-08-29 18:16:46 -0400271 def lucky_number(self):
272 return -1.375
273
Dean Moldovanbad17402016-11-20 21:21:54 +0100274 obj = BT()
275 assert obj.say_something(3) == "BTBTBT"
Jason Rhinelander20978262016-08-29 18:16:46 -0400276 assert obj.unlucky_number() == -7
277 assert obj.lucky_number() == -1.375
Dean Moldovanbad17402016-11-20 21:21:54 +0100278 assert obj.say_everything() == "BT -7"
279
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200280
Wenzel Jakob1d1f81b2016-12-16 15:00:46 +0100281# PyPy: Reference count > 1 causes call with noncopyable instance
282# to fail in ncv1.print_nc()
283@pytest.unsupported_on_pypy
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200284@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC")
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200285def test_move_support():
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200286 class NCVirtExt(m.NCVirt):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200287 def get_noncopyable(self, a, b):
288 # Constructs and returns a new instance:
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200289 nc = m.NonCopyable(a * a, b * b)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200290 return nc
291
292 def get_movable(self, a, b):
293 # Return a referenced copy
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200294 self.movable = m.Movable(a, b)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200295 return self.movable
296
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200297 class NCVirtExt2(m.NCVirt):
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200298 def get_noncopyable(self, a, b):
299 # Keep a reference: this is going to throw an exception
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200300 self.nc = m.NonCopyable(a, b)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200301 return self.nc
302
303 def get_movable(self, a, b):
304 # Return a new instance without storing it
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200305 return m.Movable(a, b)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200306
307 ncv1 = NCVirtExt()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200308 assert ncv1.print_nc(2, 3) == "36"
309 assert ncv1.print_movable(4, 5) == "9"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200310 ncv2 = NCVirtExt2()
Dean Moldovan99dbdc12016-08-19 13:45:36 +0200311 assert ncv2.print_movable(7, 7) == "14"
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200312 # Don't check the exception message here because it differs under debug/non-debug mode
313 with pytest.raises(RuntimeError):
314 ncv2.print_nc(9, 9)
315
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200316 nc_stats = ConstructorStats.get(m.NonCopyable)
317 mv_stats = ConstructorStats.get(m.Movable)
Dean Moldovana0c1ccf2016-08-12 13:50:00 +0200318 assert nc_stats.alive() == 1
319 assert mv_stats.alive() == 1
320 del ncv1, ncv2
321 assert nc_stats.alive() == 0
322 assert mv_stats.alive() == 0
323 assert nc_stats.values() == ['4', '9', '9', '9']
324 assert mv_stats.values() == ['4', '5', '7', '7']
325 assert nc_stats.copy_constructions == 0
326 assert mv_stats.copy_constructions == 1
327 assert nc_stats.move_constructions >= 0
328 assert mv_stats.move_constructions >= 0
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200329
330
331def test_dispatch_issue(msg):
332 """#159: virtual function dispatch has problems with similar-named functions"""
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200333 class PyClass1(m.DispatchIssue):
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200334 def dispatch(self):
335 return "Yay.."
336
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200337 class PyClass2(m.DispatchIssue):
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200338 def dispatch(self):
339 with pytest.raises(RuntimeError) as excinfo:
340 super(PyClass2, self).dispatch()
341 assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
342
343 p = PyClass1()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200344 return m.dispatch_issue_go(p)
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200345
346 b = PyClass2()
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200347 assert m.dispatch_issue_go(b) == "Yay.."
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200348
349
350def test_override_ref():
351 """#392/397: overridding reference-returning functions"""
Dean Moldovan0bc272b2017-06-22 23:42:11 +0200352 o = m.OverrideTest("asdf")
Dean Moldovanbdfb50f2017-06-07 16:52:50 +0200353
354 # Not allowed (see associated .cpp comment)
355 # i = o.str_ref()
356 # assert o.str_ref() == "asdf"
357 assert o.str_value() == "asdf"
358
359 assert o.A_value().value == "hi"
360 a = o.A_ref()
361 assert a.value == "hi"
362 a.value = "bye"
363 assert a.value == "bye"