test_virtual_functions.py revision 12391
111986Sandreas.sandberg@arm.comimport pytest 212391Sjason@lowepower.com 312391Sjason@lowepower.comfrom pybind11_tests import virtual_functions as m 411986Sandreas.sandberg@arm.comfrom pybind11_tests import ConstructorStats 511986Sandreas.sandberg@arm.com 611986Sandreas.sandberg@arm.com 711986Sandreas.sandberg@arm.comdef test_override(capture, msg): 812391Sjason@lowepower.com class ExtendedExampleVirt(m.ExampleVirt): 911986Sandreas.sandberg@arm.com def __init__(self, state): 1011986Sandreas.sandberg@arm.com super(ExtendedExampleVirt, self).__init__(state + 1) 1111986Sandreas.sandberg@arm.com self.data = "Hello world" 1211986Sandreas.sandberg@arm.com 1311986Sandreas.sandberg@arm.com def run(self, value): 1411986Sandreas.sandberg@arm.com print('ExtendedExampleVirt::run(%i), calling parent..' % value) 1511986Sandreas.sandberg@arm.com return super(ExtendedExampleVirt, self).run(value + 1) 1611986Sandreas.sandberg@arm.com 1711986Sandreas.sandberg@arm.com def run_bool(self): 1811986Sandreas.sandberg@arm.com print('ExtendedExampleVirt::run_bool()') 1911986Sandreas.sandberg@arm.com return False 2011986Sandreas.sandberg@arm.com 2111986Sandreas.sandberg@arm.com def get_string1(self): 2211986Sandreas.sandberg@arm.com return "override1" 2311986Sandreas.sandberg@arm.com 2411986Sandreas.sandberg@arm.com def pure_virtual(self): 2511986Sandreas.sandberg@arm.com print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) 2611986Sandreas.sandberg@arm.com 2711986Sandreas.sandberg@arm.com class ExtendedExampleVirt2(ExtendedExampleVirt): 2811986Sandreas.sandberg@arm.com def __init__(self, state): 2911986Sandreas.sandberg@arm.com super(ExtendedExampleVirt2, self).__init__(state + 1) 3011986Sandreas.sandberg@arm.com 3111986Sandreas.sandberg@arm.com def get_string2(self): 3211986Sandreas.sandberg@arm.com return "override2" 3311986Sandreas.sandberg@arm.com 3412391Sjason@lowepower.com ex12 = m.ExampleVirt(10) 3511986Sandreas.sandberg@arm.com with capture: 3612391Sjason@lowepower.com assert m.runExampleVirt(ex12, 20) == 30 3711986Sandreas.sandberg@arm.com assert capture == """ 3811986Sandreas.sandberg@arm.com Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2) 3911986Sandreas.sandberg@arm.com """ # noqa: E501 line too long 4011986Sandreas.sandberg@arm.com 4111986Sandreas.sandberg@arm.com with pytest.raises(RuntimeError) as excinfo: 4212391Sjason@lowepower.com m.runExampleVirtVirtual(ex12) 4311986Sandreas.sandberg@arm.com assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' 4411986Sandreas.sandberg@arm.com 4511986Sandreas.sandberg@arm.com ex12p = ExtendedExampleVirt(10) 4611986Sandreas.sandberg@arm.com with capture: 4712391Sjason@lowepower.com assert m.runExampleVirt(ex12p, 20) == 32 4811986Sandreas.sandberg@arm.com assert capture == """ 4911986Sandreas.sandberg@arm.com ExtendedExampleVirt::run(20), calling parent.. 5011986Sandreas.sandberg@arm.com Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) 5111986Sandreas.sandberg@arm.com """ # noqa: E501 line too long 5211986Sandreas.sandberg@arm.com with capture: 5312391Sjason@lowepower.com assert m.runExampleVirtBool(ex12p) is False 5411986Sandreas.sandberg@arm.com assert capture == "ExtendedExampleVirt::run_bool()" 5511986Sandreas.sandberg@arm.com with capture: 5612391Sjason@lowepower.com m.runExampleVirtVirtual(ex12p) 5711986Sandreas.sandberg@arm.com assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" 5811986Sandreas.sandberg@arm.com 5911986Sandreas.sandberg@arm.com ex12p2 = ExtendedExampleVirt2(15) 6011986Sandreas.sandberg@arm.com with capture: 6112391Sjason@lowepower.com assert m.runExampleVirt(ex12p2, 50) == 68 6211986Sandreas.sandberg@arm.com assert capture == """ 6311986Sandreas.sandberg@arm.com ExtendedExampleVirt::run(50), calling parent.. 6411986Sandreas.sandberg@arm.com Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) 6511986Sandreas.sandberg@arm.com """ # noqa: E501 line too long 6611986Sandreas.sandberg@arm.com 6712391Sjason@lowepower.com cstats = ConstructorStats.get(m.ExampleVirt) 6811986Sandreas.sandberg@arm.com assert cstats.alive() == 3 6911986Sandreas.sandberg@arm.com del ex12, ex12p, ex12p2 7011986Sandreas.sandberg@arm.com assert cstats.alive() == 0 7111986Sandreas.sandberg@arm.com assert cstats.values() == ['10', '11', '17'] 7211986Sandreas.sandberg@arm.com assert cstats.copy_constructions == 0 7311986Sandreas.sandberg@arm.com assert cstats.move_constructions >= 0 7411986Sandreas.sandberg@arm.com 7511986Sandreas.sandberg@arm.com 7612391Sjason@lowepower.comdef test_alias_delay_initialization1(capture): 7712391Sjason@lowepower.com """`A` only initializes its trampoline class when we inherit from it 7811986Sandreas.sandberg@arm.com 7912391Sjason@lowepower.com If we just create and use an A instance directly, the trampoline initialization is 8012391Sjason@lowepower.com bypassed and we only initialize an A() instead (for performance reasons). 8112391Sjason@lowepower.com """ 8212391Sjason@lowepower.com class B(m.A): 8312391Sjason@lowepower.com def __init__(self): 8412391Sjason@lowepower.com super(B, self).__init__() 8512391Sjason@lowepower.com 8612391Sjason@lowepower.com def f(self): 8712391Sjason@lowepower.com print("In python f()") 8812391Sjason@lowepower.com 8912391Sjason@lowepower.com # C++ version 9012391Sjason@lowepower.com with capture: 9112391Sjason@lowepower.com a = m.A() 9212391Sjason@lowepower.com m.call_f(a) 9312391Sjason@lowepower.com del a 9412391Sjason@lowepower.com pytest.gc_collect() 9512391Sjason@lowepower.com assert capture == "A.f()" 9612391Sjason@lowepower.com 9712391Sjason@lowepower.com # Python version 9812391Sjason@lowepower.com with capture: 9912391Sjason@lowepower.com b = B() 10012391Sjason@lowepower.com m.call_f(b) 10112391Sjason@lowepower.com del b 10212391Sjason@lowepower.com pytest.gc_collect() 10312391Sjason@lowepower.com assert capture == """ 10412391Sjason@lowepower.com PyA.PyA() 10512391Sjason@lowepower.com PyA.f() 10612391Sjason@lowepower.com In python f() 10712391Sjason@lowepower.com PyA.~PyA() 10812391Sjason@lowepower.com """ 10912391Sjason@lowepower.com 11012391Sjason@lowepower.com 11112391Sjason@lowepower.comdef test_alias_delay_initialization2(capture): 11212391Sjason@lowepower.com """`A2`, unlike the above, is configured to always initialize the alias 11312391Sjason@lowepower.com 11412391Sjason@lowepower.com While the extra initialization and extra class layer has small virtual dispatch 11512391Sjason@lowepower.com performance penalty, it also allows us to do more things with the trampoline 11612391Sjason@lowepower.com class such as defining local variables and performing construction/destruction. 11712391Sjason@lowepower.com """ 11812391Sjason@lowepower.com class B2(m.A2): 11912391Sjason@lowepower.com def __init__(self): 12012391Sjason@lowepower.com super(B2, self).__init__() 12112391Sjason@lowepower.com 12212391Sjason@lowepower.com def f(self): 12312391Sjason@lowepower.com print("In python B2.f()") 12412391Sjason@lowepower.com 12512391Sjason@lowepower.com # No python subclass version 12612391Sjason@lowepower.com with capture: 12712391Sjason@lowepower.com a2 = m.A2() 12812391Sjason@lowepower.com m.call_f(a2) 12912391Sjason@lowepower.com del a2 13012391Sjason@lowepower.com pytest.gc_collect() 13112391Sjason@lowepower.com a3 = m.A2(1) 13212391Sjason@lowepower.com m.call_f(a3) 13312391Sjason@lowepower.com del a3 13412391Sjason@lowepower.com pytest.gc_collect() 13512391Sjason@lowepower.com assert capture == """ 13612391Sjason@lowepower.com PyA2.PyA2() 13712391Sjason@lowepower.com PyA2.f() 13812391Sjason@lowepower.com A2.f() 13912391Sjason@lowepower.com PyA2.~PyA2() 14012391Sjason@lowepower.com PyA2.PyA2() 14112391Sjason@lowepower.com PyA2.f() 14212391Sjason@lowepower.com A2.f() 14312391Sjason@lowepower.com PyA2.~PyA2() 14412391Sjason@lowepower.com """ 14512391Sjason@lowepower.com 14612391Sjason@lowepower.com # Python subclass version 14712391Sjason@lowepower.com with capture: 14812391Sjason@lowepower.com b2 = B2() 14912391Sjason@lowepower.com m.call_f(b2) 15012391Sjason@lowepower.com del b2 15112391Sjason@lowepower.com pytest.gc_collect() 15212391Sjason@lowepower.com assert capture == """ 15312391Sjason@lowepower.com PyA2.PyA2() 15412391Sjason@lowepower.com PyA2.f() 15512391Sjason@lowepower.com In python B2.f() 15612391Sjason@lowepower.com PyA2.~PyA2() 15712391Sjason@lowepower.com """ 15812391Sjason@lowepower.com 15912391Sjason@lowepower.com 16012391Sjason@lowepower.com# PyPy: Reference count > 1 causes call with noncopyable instance 16112391Sjason@lowepower.com# to fail in ncv1.print_nc() 16212391Sjason@lowepower.com@pytest.unsupported_on_pypy 16312391Sjason@lowepower.com@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC") 16412391Sjason@lowepower.comdef test_move_support(): 16512391Sjason@lowepower.com class NCVirtExt(m.NCVirt): 16612391Sjason@lowepower.com def get_noncopyable(self, a, b): 16712391Sjason@lowepower.com # Constructs and returns a new instance: 16812391Sjason@lowepower.com nc = m.NonCopyable(a * a, b * b) 16912391Sjason@lowepower.com return nc 17012391Sjason@lowepower.com 17112391Sjason@lowepower.com def get_movable(self, a, b): 17212391Sjason@lowepower.com # Return a referenced copy 17312391Sjason@lowepower.com self.movable = m.Movable(a, b) 17412391Sjason@lowepower.com return self.movable 17512391Sjason@lowepower.com 17612391Sjason@lowepower.com class NCVirtExt2(m.NCVirt): 17712391Sjason@lowepower.com def get_noncopyable(self, a, b): 17812391Sjason@lowepower.com # Keep a reference: this is going to throw an exception 17912391Sjason@lowepower.com self.nc = m.NonCopyable(a, b) 18012391Sjason@lowepower.com return self.nc 18112391Sjason@lowepower.com 18212391Sjason@lowepower.com def get_movable(self, a, b): 18312391Sjason@lowepower.com # Return a new instance without storing it 18412391Sjason@lowepower.com return m.Movable(a, b) 18512391Sjason@lowepower.com 18612391Sjason@lowepower.com ncv1 = NCVirtExt() 18712391Sjason@lowepower.com assert ncv1.print_nc(2, 3) == "36" 18812391Sjason@lowepower.com assert ncv1.print_movable(4, 5) == "9" 18912391Sjason@lowepower.com ncv2 = NCVirtExt2() 19012391Sjason@lowepower.com assert ncv2.print_movable(7, 7) == "14" 19112391Sjason@lowepower.com # Don't check the exception message here because it differs under debug/non-debug mode 19212391Sjason@lowepower.com with pytest.raises(RuntimeError): 19312391Sjason@lowepower.com ncv2.print_nc(9, 9) 19412391Sjason@lowepower.com 19512391Sjason@lowepower.com nc_stats = ConstructorStats.get(m.NonCopyable) 19612391Sjason@lowepower.com mv_stats = ConstructorStats.get(m.Movable) 19712391Sjason@lowepower.com assert nc_stats.alive() == 1 19812391Sjason@lowepower.com assert mv_stats.alive() == 1 19912391Sjason@lowepower.com del ncv1, ncv2 20012391Sjason@lowepower.com assert nc_stats.alive() == 0 20112391Sjason@lowepower.com assert mv_stats.alive() == 0 20212391Sjason@lowepower.com assert nc_stats.values() == ['4', '9', '9', '9'] 20312391Sjason@lowepower.com assert mv_stats.values() == ['4', '5', '7', '7'] 20412391Sjason@lowepower.com assert nc_stats.copy_constructions == 0 20512391Sjason@lowepower.com assert mv_stats.copy_constructions == 1 20612391Sjason@lowepower.com assert nc_stats.move_constructions >= 0 20712391Sjason@lowepower.com assert mv_stats.move_constructions >= 0 20812391Sjason@lowepower.com 20912391Sjason@lowepower.com 21012391Sjason@lowepower.comdef test_dispatch_issue(msg): 21112391Sjason@lowepower.com """#159: virtual function dispatch has problems with similar-named functions""" 21212391Sjason@lowepower.com class PyClass1(m.DispatchIssue): 21312391Sjason@lowepower.com def dispatch(self): 21412391Sjason@lowepower.com return "Yay.." 21512391Sjason@lowepower.com 21612391Sjason@lowepower.com class PyClass2(m.DispatchIssue): 21712391Sjason@lowepower.com def dispatch(self): 21812391Sjason@lowepower.com with pytest.raises(RuntimeError) as excinfo: 21912391Sjason@lowepower.com super(PyClass2, self).dispatch() 22012391Sjason@lowepower.com assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' 22112391Sjason@lowepower.com 22212391Sjason@lowepower.com p = PyClass1() 22312391Sjason@lowepower.com return m.dispatch_issue_go(p) 22412391Sjason@lowepower.com 22512391Sjason@lowepower.com b = PyClass2() 22612391Sjason@lowepower.com assert m.dispatch_issue_go(b) == "Yay.." 22712391Sjason@lowepower.com 22812391Sjason@lowepower.com 22912391Sjason@lowepower.comdef test_override_ref(): 23012391Sjason@lowepower.com """#392/397: overridding reference-returning functions""" 23112391Sjason@lowepower.com o = m.OverrideTest("asdf") 23212391Sjason@lowepower.com 23312391Sjason@lowepower.com # Not allowed (see associated .cpp comment) 23412391Sjason@lowepower.com # i = o.str_ref() 23512391Sjason@lowepower.com # assert o.str_ref() == "asdf" 23612391Sjason@lowepower.com assert o.str_value() == "asdf" 23712391Sjason@lowepower.com 23812391Sjason@lowepower.com assert o.A_value().value == "hi" 23912391Sjason@lowepower.com a = o.A_ref() 24012391Sjason@lowepower.com assert a.value == "hi" 24112391Sjason@lowepower.com a.value = "bye" 24212391Sjason@lowepower.com assert a.value == "bye" 24312391Sjason@lowepower.com 24412391Sjason@lowepower.com 24512391Sjason@lowepower.comdef test_inherited_virtuals(): 24612391Sjason@lowepower.com class AR(m.A_Repeat): 24711986Sandreas.sandberg@arm.com def unlucky_number(self): 24811986Sandreas.sandberg@arm.com return 99 24911986Sandreas.sandberg@arm.com 25012391Sjason@lowepower.com class AT(m.A_Tpl): 25111986Sandreas.sandberg@arm.com def unlucky_number(self): 25211986Sandreas.sandberg@arm.com return 999 25311986Sandreas.sandberg@arm.com 25411986Sandreas.sandberg@arm.com obj = AR() 25511986Sandreas.sandberg@arm.com assert obj.say_something(3) == "hihihi" 25611986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 99 25711986Sandreas.sandberg@arm.com assert obj.say_everything() == "hi 99" 25811986Sandreas.sandberg@arm.com 25911986Sandreas.sandberg@arm.com obj = AT() 26011986Sandreas.sandberg@arm.com assert obj.say_something(3) == "hihihi" 26111986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 999 26211986Sandreas.sandberg@arm.com assert obj.say_everything() == "hi 999" 26311986Sandreas.sandberg@arm.com 26412391Sjason@lowepower.com for obj in [m.B_Repeat(), m.B_Tpl()]: 26511986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 26611986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 13 26711986Sandreas.sandberg@arm.com assert obj.lucky_number() == 7.0 26811986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 13" 26911986Sandreas.sandberg@arm.com 27012391Sjason@lowepower.com for obj in [m.C_Repeat(), m.C_Tpl()]: 27111986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 27211986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 27311986Sandreas.sandberg@arm.com assert obj.lucky_number() == 888.0 27411986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 27511986Sandreas.sandberg@arm.com 27612391Sjason@lowepower.com class CR(m.C_Repeat): 27711986Sandreas.sandberg@arm.com def lucky_number(self): 27812391Sjason@lowepower.com return m.C_Repeat.lucky_number(self) + 1.25 27911986Sandreas.sandberg@arm.com 28011986Sandreas.sandberg@arm.com obj = CR() 28111986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 28211986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 28311986Sandreas.sandberg@arm.com assert obj.lucky_number() == 889.25 28411986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 28511986Sandreas.sandberg@arm.com 28612391Sjason@lowepower.com class CT(m.C_Tpl): 28711986Sandreas.sandberg@arm.com pass 28811986Sandreas.sandberg@arm.com 28911986Sandreas.sandberg@arm.com obj = CT() 29011986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 29111986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 29211986Sandreas.sandberg@arm.com assert obj.lucky_number() == 888.0 29311986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 29411986Sandreas.sandberg@arm.com 29511986Sandreas.sandberg@arm.com class CCR(CR): 29611986Sandreas.sandberg@arm.com def lucky_number(self): 29711986Sandreas.sandberg@arm.com return CR.lucky_number(self) * 10 29811986Sandreas.sandberg@arm.com 29911986Sandreas.sandberg@arm.com obj = CCR() 30011986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 30111986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 30211986Sandreas.sandberg@arm.com assert obj.lucky_number() == 8892.5 30311986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 30411986Sandreas.sandberg@arm.com 30511986Sandreas.sandberg@arm.com class CCT(CT): 30611986Sandreas.sandberg@arm.com def lucky_number(self): 30711986Sandreas.sandberg@arm.com return CT.lucky_number(self) * 1000 30811986Sandreas.sandberg@arm.com 30911986Sandreas.sandberg@arm.com obj = CCT() 31011986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 31111986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 31211986Sandreas.sandberg@arm.com assert obj.lucky_number() == 888000.0 31311986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 31411986Sandreas.sandberg@arm.com 31512391Sjason@lowepower.com class DR(m.D_Repeat): 31611986Sandreas.sandberg@arm.com def unlucky_number(self): 31711986Sandreas.sandberg@arm.com return 123 31811986Sandreas.sandberg@arm.com 31911986Sandreas.sandberg@arm.com def lucky_number(self): 32011986Sandreas.sandberg@arm.com return 42.0 32111986Sandreas.sandberg@arm.com 32212391Sjason@lowepower.com for obj in [m.D_Repeat(), m.D_Tpl()]: 32311986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 32411986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 4444 32511986Sandreas.sandberg@arm.com assert obj.lucky_number() == 888.0 32611986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 4444" 32711986Sandreas.sandberg@arm.com 32811986Sandreas.sandberg@arm.com obj = DR() 32911986Sandreas.sandberg@arm.com assert obj.say_something(3) == "B says hi 3 times" 33011986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 123 33111986Sandreas.sandberg@arm.com assert obj.lucky_number() == 42.0 33211986Sandreas.sandberg@arm.com assert obj.say_everything() == "B says hi 1 times 123" 33311986Sandreas.sandberg@arm.com 33412391Sjason@lowepower.com class DT(m.D_Tpl): 33511986Sandreas.sandberg@arm.com def say_something(self, times): 33611986Sandreas.sandberg@arm.com return "DT says:" + (' quack' * times) 33711986Sandreas.sandberg@arm.com 33811986Sandreas.sandberg@arm.com def unlucky_number(self): 33911986Sandreas.sandberg@arm.com return 1234 34011986Sandreas.sandberg@arm.com 34111986Sandreas.sandberg@arm.com def lucky_number(self): 34211986Sandreas.sandberg@arm.com return -4.25 34311986Sandreas.sandberg@arm.com 34411986Sandreas.sandberg@arm.com obj = DT() 34511986Sandreas.sandberg@arm.com assert obj.say_something(3) == "DT says: quack quack quack" 34611986Sandreas.sandberg@arm.com assert obj.unlucky_number() == 1234 34711986Sandreas.sandberg@arm.com assert obj.lucky_number() == -4.25 34811986Sandreas.sandberg@arm.com assert obj.say_everything() == "DT says: quack 1234" 34911986Sandreas.sandberg@arm.com 35011986Sandreas.sandberg@arm.com class DT2(DT): 35111986Sandreas.sandberg@arm.com def say_something(self, times): 35211986Sandreas.sandberg@arm.com return "DT2: " + ('QUACK' * times) 35311986Sandreas.sandberg@arm.com 35411986Sandreas.sandberg@arm.com def unlucky_number(self): 35511986Sandreas.sandberg@arm.com return -3 35611986Sandreas.sandberg@arm.com 35712391Sjason@lowepower.com class BT(m.B_Tpl): 35811986Sandreas.sandberg@arm.com def say_something(self, times): 35911986Sandreas.sandberg@arm.com return "BT" * times 36011986Sandreas.sandberg@arm.com 36111986Sandreas.sandberg@arm.com def unlucky_number(self): 36211986Sandreas.sandberg@arm.com return -7 36311986Sandreas.sandberg@arm.com 36411986Sandreas.sandberg@arm.com def lucky_number(self): 36511986Sandreas.sandberg@arm.com return -1.375 36611986Sandreas.sandberg@arm.com 36711986Sandreas.sandberg@arm.com obj = BT() 36811986Sandreas.sandberg@arm.com assert obj.say_something(3) == "BTBTBT" 36911986Sandreas.sandberg@arm.com assert obj.unlucky_number() == -7 37011986Sandreas.sandberg@arm.com assert obj.lucky_number() == -1.375 37111986Sandreas.sandberg@arm.com assert obj.say_everything() == "BT -7" 372