test_issues.cpp 12 KB
Newer Older
1
/*
Dean Moldovan's avatar
Dean Moldovan committed
2
    tests/test_issues.cpp -- collection of testcases for miscellaneous issues
3

4
    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5
6
7
8
9

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

Dean Moldovan's avatar
Dean Moldovan committed
10
11
#include "pybind11_tests.h"
#include "constructor_stats.h"
12
#include <pybind11/stl.h>
13
#include <pybind11/operators.h>
14

Wenzel Jakob's avatar
Wenzel Jakob committed
15

16
17
18
19
20
21
#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
struct NestABase { int value = -2; TRACKERS(NestABase) };
struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// #393
class OpTest1 {};
class OpTest2 {};

OpTest1 operator+(const OpTest1 &, const OpTest1 &) {
    py::print("Add OpTest1 with OpTest1");
    return OpTest1();
}
OpTest2 operator+(const OpTest2 &, const OpTest2 &) {
    py::print("Add OpTest2 with OpTest2");
    return OpTest2();
}
OpTest2 operator+(const OpTest2 &, const OpTest1 &) {
    py::print("Add OpTest2 with OpTest1");
    return OpTest2();
}

39
40
41
42
43
44
45
46
47
48
49
50
// #461
class Dupe1 {
public:
    Dupe1(int v) : v_{v} {}
    int get_value() const { return v_; }
private:
    int v_;
};
class Dupe2 {};
class Dupe3 {};
class DupeException : public std::runtime_error {};

51
52
53
void init_issues(py::module &m) {
    py::module m2 = m.def_submodule("issues");

Wenzel Jakob's avatar
Wenzel Jakob committed
54
55
56
57
58
59
#if !defined(_MSC_VER)
    // Visual Studio 2015 currently cannot compile this test
    // (see the comment in type_caster_base::make_copy_constructor)
    // #70 compilation issue if operator new is not public
    class NonConstructible { private: void *operator new(size_t bytes) throw(); };
    py::class_<NonConstructible>(m, "Foo");
60
    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
Wenzel Jakob's avatar
Wenzel Jakob committed
61
62
63
        py::return_value_policy::reference);
#endif

64
    // #137: const char* isn't handled properly
65
    m2.def("print_cchar", [](const char *s) { return std::string(s); });
66
67

    // #150: char bindings broken
68
    m2.def("print_char", [](char c) { return std::string(1, c); });
69
70

    // #159: virtual function dispatch has problems with similar-named functions
71
    struct Base { virtual std::string dispatch() const {
Wenzel Jakob's avatar
Wenzel Jakob committed
72
        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
73
        return {};
Wenzel Jakob's avatar
Wenzel Jakob committed
74
    }; };
Wenzel Jakob's avatar
Wenzel Jakob committed
75
76

    struct DispatchIssue : Base {
77
78
        virtual std::string dispatch() const {
            PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
Wenzel Jakob's avatar
Wenzel Jakob committed
79
80
81
        }
    };

82
    py::class_<Base, DispatchIssue>(m2, "DispatchIssue")
83
        .def(py::init<>())
84
85
        .def("dispatch", &Base::dispatch);

86
    m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
Wenzel Jakob's avatar
Wenzel Jakob committed
87
88

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
89
90

    py::class_<Placeholder>(m2, "Placeholder")
91
        .def(py::init<int>())
92
93
94
        .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; });

    // #171: Can't return reference wrappers (or STL datastructures containing them)
Wenzel Jakob's avatar
Wenzel Jakob committed
95
    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4) {
96
97
        Placeholder *p1 = new Placeholder{1};
        Placeholder *p2 = new Placeholder{2};
98
        Placeholder *p3 = new Placeholder{3};
99
100
101
102
        std::vector<std::reference_wrapper<Placeholder>> v;
        v.push_back(std::ref(*p1));
        v.push_back(std::ref(*p2));
        v.push_back(std::ref(*p3));
103
        v.push_back(p4);
104
105
        return v;
    });
106
107
108
109
110

    // #181: iterator passthrough did not compile
    m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
        return py::make_iterator(std::begin(s), std::end(s));
    });
Wenzel Jakob's avatar
Wenzel Jakob committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

    // #187: issue involving std::shared_ptr<> return value policy & garbage collection
    struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
    struct ElementA : ElementBase {
        ElementA(int v) : v(v) { }
        int value() { return v; }
        int v;
    };

    struct ElementList {
        void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
        std::vector<std::shared_ptr<ElementBase>> l;
    };

    py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");

127
    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
Wenzel Jakob's avatar
Wenzel Jakob committed
128
129
130
131
132
133
        .def(py::init<int>())
        .def("value", &ElementA::value);

    py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
        .def(py::init<>())
        .def("add", &ElementList::add)
Wenzel Jakob's avatar
Wenzel Jakob committed
134
        .def("get", [](ElementList &el) {
Wenzel Jakob's avatar
Wenzel Jakob committed
135
136
137
138
139
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
140
141

    // (no id): should not be able to pass 'None' to a reference argument
142
    m2.def("get_element", [](ElementA &el) { return el.value(); });
143
144
145
146

    // (no id): don't cast doubles to ints
    m2.def("expect_float", [](float f) { return f; });
    m2.def("expect_int", [](int i) { return i; });
147

148
149
150
    try {
        py::class_<Placeholder>(m2, "Placeholder");
        throw std::logic_error("Expected an exception!");
Dean Moldovan's avatar
Dean Moldovan committed
151
    } catch (std::runtime_error &) {
152
153
        /* All good */
    }
154
155
156
157
158
159
160
161
162
163
164
165
166

    // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
    class StrIssue {
    public:
        StrIssue(int i) : val{i} {}
        StrIssue() : StrIssue(-1) {}
        int value() const { return val; }
    private:
        int val;
    };
    py::class_<StrIssue> si(m2, "StrIssue");
    si  .def(py::init<int>())
        .def(py::init<>())
167
        .def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; })
168
169
        ;

170
    // Issue #328: first member in a class can't be used in operators
171
172
173
    py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
    py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
        .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
174
175
    py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
    py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
176
177
178
    m2.def("get_NestA", [](const NestA &a) { return a.value; });
    m2.def("get_NestB", [](const NestB &b) { return b.value; });
    m2.def("get_NestC", [](const NestC &c) { return c.value; });
179
180
181
182
183

    // Issue 389: r_v_p::move should fall-through to copy on non-movable objects
    class MoveIssue1 {
    public:
        MoveIssue1(int v) : v{v} {}
184
        MoveIssue1(const MoveIssue1 &c) { v = c.v; }
185
186
187
188
189
190
191
192
193
194
195
196
197
        MoveIssue1(MoveIssue1 &&) = delete;
        int v;
    };
    class MoveIssue2 {
    public:
        MoveIssue2(int v) : v{v} {}
        MoveIssue2(MoveIssue2 &&) = default;
        int v;
    };
    py::class_<MoveIssue1>(m2, "MoveIssue1").def(py::init<int>()).def_readwrite("value", &MoveIssue1::v);
    py::class_<MoveIssue2>(m2, "MoveIssue2").def(py::init<int>()).def_readwrite("value", &MoveIssue2::v);
    m2.def("get_moveissue1", [](int i) -> MoveIssue1 * { return new MoveIssue1(i); }, py::return_value_policy::move);
    m2.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move);
198

199
    // Issues 392/397: overridding reference-returning functions
200
201
    class OverrideTest {
    public:
202
203
        struct A { std::string value = "hi"; };
        std::string v;
204
        A a;
205
206
207
        explicit OverrideTest(const std::string &v) : v{v} {}
        virtual std::string str_value() { return v; }
        virtual std::string &str_ref() { return v; }
208
209
210
211
212
213
        virtual A A_value() { return a; }
        virtual A &A_ref() { return a; }
    };
    class PyOverrideTest : public OverrideTest {
    public:
        using OverrideTest::OverrideTest;
214
        std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
215
216
        // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
        // to a python numeric value, since we only copy values in the numeric type caster:
217
218
219
220
221
222
223
224
//      std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); }
        // But we can work around it like this:
    private:
        std::string _tmp;
        std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); }
    public:
        std::string &str_ref() override { return _tmp = str_ref_helper(); }

225
226
227
228
229
230
        A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); }
        A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); }
    };
    py::class_<OverrideTest::A>(m2, "OverrideTest_A")
        .def_readwrite("value", &OverrideTest::A::value);
    py::class_<OverrideTest, PyOverrideTest>(m2, "OverrideTest")
231
232
233
        .def(py::init<const std::string &>())
        .def("str_value", &OverrideTest::str_value)
//      .def("str_ref", &OverrideTest::str_ref)
234
235
        .def("A_value", &OverrideTest::A_value)
        .def("A_ref", &OverrideTest::A_ref);
236

237
238
239
240
241
242
243
244
245
246
    /// Issue 393: need to return NotSupported to ensure correct arithmetic operator behavior
    py::class_<OpTest1>(m2, "OpTest1")
        .def(py::init<>())
        .def(py::self + py::self);

    py::class_<OpTest2>(m2, "OpTest2")
        .def(py::init<>())
        .def(py::self + py::self)
        .def("__add__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; })
        .def("__radd__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; });
247
248
249
250
251

    // Issue 388: Can't make iterators via make_iterator() with different r/v policies
    static std::vector<int> list = { 1, 2, 3 };
    m2.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); });
    m2.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); });
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

    static std::vector<std::string> nothrows;
    // Issue 461: registering two things with the same name:
    py::class_<Dupe1>(m2, "Dupe1")
        .def("get_value", &Dupe1::get_value)
        ;
    m2.def("dupe1_factory", [](int v) { return new Dupe1(v); });

    py::class_<Dupe2>(m2, "Dupe2");
    py::exception<DupeException>(m2, "DupeException");

    try {
        m2.def("Dupe1", [](int v) { return new Dupe1(v); });
        nothrows.emplace_back("Dupe1");
    }
    catch (std::runtime_error &) {}
    try {
        py::class_<Dupe3>(m2, "dupe1_factory");
        nothrows.emplace_back("dupe1_factory");
    }
    catch (std::runtime_error &) {}
    try {
        py::exception<Dupe3>(m2, "Dupe2");
        nothrows.emplace_back("Dupe2");
    }
    catch (std::runtime_error &) {}
    try {
        m2.def("DupeException", []() { return 30; });
        nothrows.emplace_back("DupeException1");
    }
    catch (std::runtime_error &) {}
    try {
        py::class_<DupeException>(m2, "DupeException");
        nothrows.emplace_back("DupeException2");
    }
    catch (std::runtime_error &) {}
    m2.def("dupe_exception_failures", []() {
        py::list l;
        for (auto &e : nothrows) l.append(py::cast(e));
        return l;
    });
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

    /// Issue #471: shared pointer instance not dellocated
    class SharedChild : public std::enable_shared_from_this<SharedChild> {
    public:
        SharedChild() { print_created(this); }
        ~SharedChild() { print_destroyed(this); }
    };

    class SharedParent {
    public:
        SharedParent() : child(std::make_shared<SharedChild>()) { }
        const SharedChild &get_child() const { return *child; }

    private:
        std::shared_ptr<SharedChild> child;
    };

    py::class_<SharedChild, std::shared_ptr<SharedChild>>(m, "SharedChild");
    py::class_<SharedParent, std::shared_ptr<SharedParent>>(m, "SharedParent")
        .def(py::init<>())
        .def("get_child", &SharedParent::get_child, py::return_value_policy::reference);
};
315

316

317
318
// MSVC workaround: trying to use a lambda here crashes MSCV
test_initializer issues(&init_issues);