test_virtual_functions.py 6.13 KB
Newer Older
Dean Moldovan's avatar
Dean Moldovan committed
1
2
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
import pytest
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


57
def test_inheriting_repeat():
Dean Moldovan's avatar
Dean Moldovan committed
58
59
60
61
62
63
64
65
66
67
68
    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()
69
    assert obj.say_something(3) == "hihihi"
Dean Moldovan's avatar
Dean Moldovan committed
70
71
72
    assert obj.unlucky_number() == 99

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

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

    for obj in [C_Repeat(), C_Tpl()]:
82
        assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
83
84
85
86
87
88
89
90
        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()
91
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
92
93
94
95
96
97
98
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 889.25

    class VI_CT(C_Tpl):
        pass

    obj = VI_CT()
99
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
100
101
102
103
104
105
106
107
    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()
108
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
109
110
111
112
113
114
115
116
    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()
117
    assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
118
119
120
121
122
123
124
125
126
127
128
    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()]:
129
        assert obj.say_something(3) == "B says hi 3 times"
Dean Moldovan's avatar
Dean Moldovan committed
130
131
132
133
        assert obj.unlucky_number() == 4444
        assert obj.lucky_number() == 888.0

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

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

        def unlucky_number(self):
            return 1234

        def lucky_number(self):
            return -4.25

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


154
def test_move_support():
Dean Moldovan's avatar
Dean Moldovan committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    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()
179
180
    assert ncv1.print_nc(2, 3) == "36"
    assert ncv1.print_movable(4, 5) == "9"
Dean Moldovan's avatar
Dean Moldovan committed
181
    ncv2 = NCVirtExt2()
182
    assert ncv2.print_movable(7, 7) == "14"
Dean Moldovan's avatar
Dean Moldovan committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
    # 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