test_issues.cpp 15.5 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
#include <pybind11/complex.h>
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
// #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>);

67
68
69
70
71
72
73
74
75
/// Issue #528: templated constructor
struct TplConstrClass {
    template <typename T> TplConstrClass(const T &arg) : str{arg} {}
    std::string str;
    bool operator==(const TplConstrClass &t) const { return t.str == str; }
};
namespace std {
template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass &t) const { return std::hash<std::string>()(t.str); } };
}
76
77


78
79
80
void init_issues(py::module &m) {
    py::module m2 = m.def_submodule("issues");

Wenzel Jakob's avatar
Wenzel Jakob committed
81
82
83
84
85
86
#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");
87
    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
Wenzel Jakob's avatar
Wenzel Jakob committed
88
89
90
        py::return_value_policy::reference);
#endif

91
    // #137: const char* isn't handled properly
92
    m2.def("print_cchar", [](const char *s) { return std::string(s); });
93
94

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

    // #159: virtual function dispatch has problems with similar-named functions
98
    struct Base { virtual std::string dispatch() const {
Wenzel Jakob's avatar
Wenzel Jakob committed
99
        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
100
        return {};
Wenzel Jakob's avatar
Wenzel Jakob committed
101
    }; };
Wenzel Jakob's avatar
Wenzel Jakob committed
102
103

    struct DispatchIssue : Base {
104
105
        virtual std::string dispatch() const {
            PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
Wenzel Jakob's avatar
Wenzel Jakob committed
106
107
108
        }
    };

109
    py::class_<Base, DispatchIssue>(m2, "DispatchIssue")
110
        .def(py::init<>())
111
112
        .def("dispatch", &Base::dispatch);

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

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
116
117

    py::class_<Placeholder>(m2, "Placeholder")
118
        .def(py::init<int>())
119
120
121
        .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
122
    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4) {
123
124
        Placeholder *p1 = new Placeholder{1};
        Placeholder *p2 = new Placeholder{2};
125
        Placeholder *p3 = new Placeholder{3};
126
127
128
129
        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));
130
        v.push_back(p4);
131
132
        return v;
    });
133
134
135
136
137

    // #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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

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

154
    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
Wenzel Jakob's avatar
Wenzel Jakob committed
155
156
157
158
159
160
        .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
161
        .def("get", [](ElementList &el) {
Wenzel Jakob's avatar
Wenzel Jakob committed
162
163
164
165
166
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
167
168

    // (no id): should not be able to pass 'None' to a reference argument
169
    m2.def("get_element", [](ElementA &el) { return el.value(); });
170
171
172
173

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

175
176
177
    try {
        py::class_<Placeholder>(m2, "Placeholder");
        throw std::logic_error("Expected an exception!");
Dean Moldovan's avatar
Dean Moldovan committed
178
    } catch (std::runtime_error &) {
179
180
        /* All good */
    }
181
182
183
184
185
186
187
188
189
190
191
192
193

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

197
    // Issue #328: first member in a class can't be used in operators
198
199
200
    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);
201
202
    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);
203
204
205
    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; });
206
207
208
209
210

    // Issue 389: r_v_p::move should fall-through to copy on non-movable objects
    class MoveIssue1 {
    public:
        MoveIssue1(int v) : v{v} {}
211
        MoveIssue1(const MoveIssue1 &c) { v = c.v; }
212
213
214
215
216
217
218
219
220
221
222
223
224
        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);
225

226
    // Issues 392/397: overridding reference-returning functions
227
228
    class OverrideTest {
    public:
229
230
        struct A { std::string value = "hi"; };
        std::string v;
231
        A a;
232
233
234
        explicit OverrideTest(const std::string &v) : v{v} {}
        virtual std::string str_value() { return v; }
        virtual std::string &str_ref() { return v; }
235
236
237
238
239
240
        virtual A A_value() { return a; }
        virtual A &A_ref() { return a; }
    };
    class PyOverrideTest : public OverrideTest {
    public:
        using OverrideTest::OverrideTest;
241
        std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
242
243
        // 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:
244
245
246
247
248
249
250
251
//      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(); }

252
253
254
255
256
257
        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")
258
259
260
        .def(py::init<const std::string &>())
        .def("str_value", &OverrideTest::str_value)
//      .def("str_ref", &OverrideTest::str_ref)
261
262
        .def("A_value", &OverrideTest::A_value)
        .def("A_ref", &OverrideTest::A_ref);
263

264
265
266
267
268
269
270
271
272
273
    /// 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; });
274
275
276
277
278

    // 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); });
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
311
312
313
314
315
316
317
318
319

    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;
    });
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340

    /// 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);
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357

    /// 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>>,
358
                py::return_value_policy::reference);
359

360
361
362
    /// Issue #484: number conversion generates unhandled exceptions
    m2.def("test_complex", [](float x) { py::print("{}"_s.format(x)); });
    m2.def("test_complex", [](std::complex<float> x) { py::print("({}, {})"_s.format(x.real(), x.imag())); });
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

    /// Issue #511: problem with inheritance + overwritten def_static
    struct MyBase {
        static std::unique_ptr<MyBase> make() {
            return std::unique_ptr<MyBase>(new MyBase());
        }
    };

    struct MyDerived : MyBase {
        static std::unique_ptr<MyDerived> make() {
            return std::unique_ptr<MyDerived>(new MyDerived());
        }
    };

    py::class_<MyBase>(m2, "MyBase")
        .def_static("make", &MyBase::make);

    py::class_<MyDerived, MyBase>(m2, "MyDerived")
        .def_static("make", &MyDerived::make)
        .def_static("make2", &MyDerived::make);
383

384
385
386
387
388
    py::dict d;
    std::string bar = "bar";
    d["str"] = bar;
    d["num"] = 3.7;

389
390
391
392
393
394
395
396
397
    /// Issue #528: templated constructor
    m2.def("tpl_constr_vector", [](std::vector<TplConstrClass> &) {});
    m2.def("tpl_constr_map", [](std::unordered_map<TplConstrClass, TplConstrClass> &) {});
    m2.def("tpl_constr_set", [](std::unordered_set<TplConstrClass> &) {});
#if defined(PYBIND11_HAS_OPTIONAL)
    m2.def("tpl_constr_optional", [](std::optional<TplConstrClass> &) {});
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
    m2.def("tpl_constr_optional", [](std::experimental::optional<TplConstrClass> &) {});
#endif
398
}
399

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