test_issues.cpp 13.7 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// #478
template <typename T> class custom_unique_ptr {
public:
    custom_unique_ptr() { print_default_created(this); }
    custom_unique_ptr(T *ptr) : _ptr{ptr} { print_created(this, ptr); }
    custom_unique_ptr(custom_unique_ptr<T> &&move) : _ptr{move._ptr} { move._ptr = nullptr; print_move_created(this); }
    custom_unique_ptr &operator=(custom_unique_ptr<T> &&move) { print_move_assigned(this); if (_ptr) destruct_ptr(); _ptr = move._ptr; move._ptr = nullptr; return *this; }
    custom_unique_ptr(const custom_unique_ptr<T> &) = delete;
    void operator=(const custom_unique_ptr<T> &copy) = delete;
    ~custom_unique_ptr() { print_destroyed(this); if (_ptr) destruct_ptr(); }
private:
    T *_ptr = nullptr;
    void destruct_ptr() { delete _ptr; }
};
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);



69
70
71
void init_issues(py::module &m) {
    py::module m2 = m.def_submodule("issues");

Wenzel Jakob's avatar
Wenzel Jakob committed
72
73
74
75
76
77
#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");
78
    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
Wenzel Jakob's avatar
Wenzel Jakob committed
79
80
81
        py::return_value_policy::reference);
#endif

82
    // #137: const char* isn't handled properly
83
    m2.def("print_cchar", [](const char *s) { return std::string(s); });
84
85

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

    // #159: virtual function dispatch has problems with similar-named functions
89
    struct Base { virtual std::string dispatch() const {
Wenzel Jakob's avatar
Wenzel Jakob committed
90
        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
91
        return {};
Wenzel Jakob's avatar
Wenzel Jakob committed
92
    }; };
Wenzel Jakob's avatar
Wenzel Jakob committed
93
94

    struct DispatchIssue : Base {
95
96
        virtual std::string dispatch() const {
            PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
Wenzel Jakob's avatar
Wenzel Jakob committed
97
98
99
        }
    };

100
    py::class_<Base, DispatchIssue>(m2, "DispatchIssue")
101
        .def(py::init<>())
102
103
        .def("dispatch", &Base::dispatch);

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

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
107
108

    py::class_<Placeholder>(m2, "Placeholder")
109
        .def(py::init<int>())
110
111
112
        .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
113
    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4) {
114
115
        Placeholder *p1 = new Placeholder{1};
        Placeholder *p2 = new Placeholder{2};
116
        Placeholder *p3 = new Placeholder{3};
117
118
119
120
        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));
121
        v.push_back(p4);
122
123
        return v;
    });
124
125
126
127
128

    // #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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

    // #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");

145
    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
Wenzel Jakob's avatar
Wenzel Jakob committed
146
147
148
149
150
151
        .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
152
        .def("get", [](ElementList &el) {
Wenzel Jakob's avatar
Wenzel Jakob committed
153
154
155
156
157
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
158
159

    // (no id): should not be able to pass 'None' to a reference argument
160
    m2.def("get_element", [](ElementA &el) { return el.value(); });
161
162
163
164

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

166
167
168
    try {
        py::class_<Placeholder>(m2, "Placeholder");
        throw std::logic_error("Expected an exception!");
Dean Moldovan's avatar
Dean Moldovan committed
169
    } catch (std::runtime_error &) {
170
171
        /* All good */
    }
172
173
174
175
176
177
178
179
180
181
182
183
184

    // 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<>())
185
        .def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; })
186
187
        ;

188
    // Issue #328: first member in a class can't be used in operators
189
190
191
    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);
192
193
    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);
194
195
196
    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; });
197
198
199
200
201

    // Issue 389: r_v_p::move should fall-through to copy on non-movable objects
    class MoveIssue1 {
    public:
        MoveIssue1(int v) : v{v} {}
202
        MoveIssue1(const MoveIssue1 &c) { v = c.v; }
203
204
205
206
207
208
209
210
211
212
213
214
215
        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);
216

217
    // Issues 392/397: overridding reference-returning functions
218
219
    class OverrideTest {
    public:
220
221
        struct A { std::string value = "hi"; };
        std::string v;
222
        A a;
223
224
225
        explicit OverrideTest(const std::string &v) : v{v} {}
        virtual std::string str_value() { return v; }
        virtual std::string &str_ref() { return v; }
226
227
228
229
230
231
        virtual A A_value() { return a; }
        virtual A &A_ref() { return a; }
    };
    class PyOverrideTest : public OverrideTest {
    public:
        using OverrideTest::OverrideTest;
232
        std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
233
234
        // 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:
235
236
237
238
239
240
241
242
//      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(); }

243
244
245
246
247
248
        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")
249
250
251
        .def(py::init<const std::string &>())
        .def("str_value", &OverrideTest::str_value)
//      .def("str_ref", &OverrideTest::str_ref)
252
253
        .def("A_value", &OverrideTest::A_value)
        .def("A_ref", &OverrideTest::A_ref);
254

255
256
257
258
259
260
261
262
263
264
    /// 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; });
265
266
267
268
269

    // 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); });
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

    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;
    });
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

    /// 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);
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350

    /// Issue/PR #478: unique ptrs constructed and freed without destruction
    class SpecialHolderObj {
    public:
        int val = 0;
        SpecialHolderObj *ch = nullptr;
        SpecialHolderObj(int v, bool make_child = true) : val{v}, ch{make_child ? new SpecialHolderObj(val+1, false) : nullptr}
        { print_created(this, val); }
        ~SpecialHolderObj() { delete ch; print_destroyed(this); }
        SpecialHolderObj *child() { return ch; }
    };

    py::class_<SpecialHolderObj, custom_unique_ptr<SpecialHolderObj>>(m, "SpecialHolderObj")
        .def(py::init<int>())
        .def("child", &SpecialHolderObj::child, pybind11::return_value_policy::reference_internal)
        .def_readwrite("val", &SpecialHolderObj::val)
        .def_static("holder_cstats", &ConstructorStats::get<custom_unique_ptr<SpecialHolderObj>>,
                py::return_value_policy::reference)
        ;
351
};
352

353

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