test_virtual_functions.py 6.64 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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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


def test_inheriting_repeat(capture):
    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()
    with capture:
        obj.say_something(3)
    assert capture == "hihihi"
    assert obj.unlucky_number() == 99

    obj = VI_AT()
    with capture:
        obj.say_something(3)
    assert capture == "hihihi"
    assert obj.unlucky_number() == 999

    for obj in [B_Repeat(), B_Tpl()]:
        with capture:
            obj.say_something(3)
        assert capture == "B says hi 3 times"
        assert obj.unlucky_number() == 13
        assert obj.lucky_number() == 7.0

    for obj in [C_Repeat(), C_Tpl()]:
        with capture:
            obj.say_something(3)
        assert capture == "B says hi 3 times"
        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()
    with capture:
        obj.say_something(3)
    assert capture == "B says hi 3 times"
    assert obj.unlucky_number() == 4444
    assert obj.lucky_number() == 889.25

    class VI_CT(C_Tpl):
        pass

    obj = VI_CT()
    with capture:
        obj.say_something(3)
    assert capture == "B says hi 3 times"
    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()
    with capture:
        obj.say_something(3)
    assert capture == "B says hi 3 times"
    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()
    with capture:
        obj.say_something(3)
    assert capture == "B says hi 3 times"
    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()]:
        with capture:
            obj.say_something(3)
        assert capture == "B says hi 3 times"
        assert obj.unlucky_number() == 4444
        assert obj.lucky_number() == 888.0

    obj = VI_DR()
    with capture:
        obj.say_something(3)
    assert capture == "B says hi 3 times"
    assert obj.unlucky_number() == 123
    assert obj.lucky_number() == 42.0

    class VI_DT(D_Tpl):
        def say_something(self, times):
            print("VI_DT says:" + (' quack' * times))

        def unlucky_number(self):
            return 1234

        def lucky_number(self):
            return -4.25

    obj = VI_DT()
    with capture:
        obj.say_something(3)
    assert capture == "VI_DT says: quack quack quack"
    assert obj.unlucky_number() == 1234
    assert obj.lucky_number() == -4.25


176
def test_move_support(capture):
Dean Moldovan's avatar
Dean Moldovan committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    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()
    with capture:
        ncv1.print_nc(2, 3)
    assert capture == "36"
    with capture:
        ncv1.print_movable(4, 5)
    assert capture == "9"
    ncv2 = NCVirtExt2()
    with capture:
        ncv2.print_movable(7, 7)
    assert capture == "14"
    # 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