test_virtual_functions.py 6.21 KB
Newer Older
Dean Moldovan's avatar
Dean Moldovan committed
1
import pytest
2
import pybind11_tests
Dean Moldovan's avatar
Dean Moldovan committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from pybind11_tests import ConstructorStats


def test_override(capture, msg):
    from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual,
                                runExampleVirtBool)

    class ExtendedExampleVirt(ExampleVirt):
        def __init__(self, state):
            super(ExtendedExampleVirt, self).__init__(state + 1)
            self.data = "Hello world"

        def run(self, value):
            print('ExtendedExampleVirt::run(%i), calling parent..' % value)
            return super(ExtendedExampleVirt, self).run(value + 1)

        def run_bool(self):
            print('ExtendedExampleVirt::run_bool()')
            return False

        def pure_virtual(self):
            print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)

    ex12 = ExampleVirt(10)
    with capture:
        assert runExampleVirt(ex12, 20) == 30
    assert capture == "Original implementation of ExampleVirt::run(state=10, value=20)"

    with pytest.raises(RuntimeError) as excinfo:
        runExampleVirtVirtual(ex12)
    assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'

    ex12p = ExtendedExampleVirt(10)
    with capture:
        assert runExampleVirt(ex12p, 20) == 32
    assert capture == """
        ExtendedExampleVirt::run(20), calling parent..
        Original implementation of ExampleVirt::run(state=11, value=21)
    """
    with capture:
        assert runExampleVirtBool(ex12p) is False
    assert capture == "ExtendedExampleVirt::run_bool()"
    with capture:
        runExampleVirtVirtual(ex12p)
    assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"

    cstats = ConstructorStats.get(ExampleVirt)
    assert cstats.alive() == 2
    del ex12, ex12p
    assert cstats.alive() == 0
    assert cstats.values() == ['10', '11']
    assert cstats.copy_constructions == 0
    assert cstats.move_constructions >= 0


58
def test_inheriting_repeat():
Dean Moldovan's avatar
Dean Moldovan committed
59
60
61
62
63
64
65
66
67
68
69
    from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl

    class VI_AR(A_Repeat):
        def unlucky_number(self):
            return 99

    class VI_AT(A_Tpl):
        def unlucky_number(self):
            return 999

    obj = VI_AR()
70
    assert obj.say_something(3) == "hihihi"
Dean Moldovan's avatar
Dean Moldovan committed
71
72
73
    assert obj.unlucky_number() == 99

    obj = VI_AT()
74
    assert obj.say_something(3) == "hihihi"
Dean Moldovan's avatar
Dean Moldovan committed
75
76
77
    assert obj.unlucky_number() == 999

    for obj in [B_Repeat(), B_Tpl()]:
78
        assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
79
80
81
82
        assert obj.unlucky_number() == 13
        assert obj.lucky_number() == 7.0

    for obj in [C_Repeat(), C_Tpl()]:
83
        assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
84
85
86
87
88
89
90
91
        assert obj.unlucky_number() == 4444
        assert obj.lucky_number() == 888.0

    class VI_CR(C_Repeat):
        def lucky_number(self):
            return C_Repeat.lucky_number(self) + 1.25

    obj = VI_CR()
92
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
93
94
95
96
97
98
99
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 889.25

    class VI_CT(C_Tpl):
        pass

    obj = VI_CT()
100
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
101
102
103
104
105
106
107
108
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 888.0

    class VI_CCR(VI_CR):
        def lucky_number(self):
            return VI_CR.lucky_number(self) * 10

    obj = VI_CCR()
109
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
110
111
112
113
114
115
116
117
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 8892.5

    class VI_CCT(VI_CT):
        def lucky_number(self):
            return VI_CT.lucky_number(self) * 1000

    obj = VI_CCT()
118
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
119
120
121
122
123
124
125
126
127
128
129
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 888000.0

    class VI_DR(D_Repeat):
        def unlucky_number(self):
            return 123

        def lucky_number(self):
            return 42.0

    for obj in [D_Repeat(), D_Tpl()]:
130
        assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
131
132
133
134
        assert obj.unlucky_number() == 4444
        assert obj.lucky_number() == 888.0

    obj = VI_DR()
135
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
136
137
138
139
140
    assert obj.unlucky_number() == 123
    assert obj.lucky_number() == 42.0

    class VI_DT(D_Tpl):
        def say_something(self, times):
141
            return "VI_DT says:" + (' quack' * times)
Dean Moldovan's avatar
Dean Moldovan committed
142
143
144
145
146
147
148
149

        def unlucky_number(self):
            return 1234

        def lucky_number(self):
            return -4.25

    obj = VI_DT()
150
    assert obj.say_something(3) == "VI_DT says: quack quack quack"
Dean Moldovan's avatar
Dean Moldovan committed
151
152
153
    assert obj.unlucky_number() == 1234
    assert obj.lucky_number() == -4.25

154
@pytest.mark.skipif(not hasattr(pybind11_tests, 'NCVirt'))
155
def test_move_support():
Dean Moldovan's avatar
Dean Moldovan committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    from pybind11_tests import NCVirt, NonCopyable, Movable

    class NCVirtExt(NCVirt):
        def get_noncopyable(self, a, b):
            # Constructs and returns a new instance:
            nc = NonCopyable(a*a, b*b)
            return nc

        def get_movable(self, a, b):
            # Return a referenced copy
            self.movable = Movable(a, b)
            return self.movable

    class NCVirtExt2(NCVirt):
        def get_noncopyable(self, a, b):
            # Keep a reference: this is going to throw an exception
            self.nc = NonCopyable(a, b)
            return self.nc

        def get_movable(self, a, b):
            # Return a new instance without storing it
            return Movable(a, b)

    ncv1 = NCVirtExt()
180
181
    assert ncv1.print_nc(2, 3) == "36"
    assert ncv1.print_movable(4, 5) == "9"
Dean Moldovan's avatar
Dean Moldovan committed
182
    ncv2 = NCVirtExt2()
183
    assert ncv2.print_movable(7, 7) == "14"
Dean Moldovan's avatar
Dean Moldovan committed
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    # Don't check the exception message here because it differs under debug/non-debug mode
    with pytest.raises(RuntimeError):
        ncv2.print_nc(9, 9)

    nc_stats = ConstructorStats.get(NonCopyable)
    mv_stats = ConstructorStats.get(Movable)
    assert nc_stats.alive() == 1
    assert mv_stats.alive() == 1
    del ncv1, ncv2
    assert nc_stats.alive() == 0
    assert mv_stats.alive() == 0
    assert nc_stats.values() == ['4', '9', '9', '9']
    assert mv_stats.values() == ['4', '5', '7', '7']
    assert nc_stats.copy_constructions == 0
    assert mv_stats.copy_constructions == 1
    assert nc_stats.move_constructions >= 0
    assert mv_stats.move_constructions >= 0