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