test_issues.cpp 14.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");

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

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

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

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

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

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

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
105
106

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

110
111
112
113
    // #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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

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

130
    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
Wenzel Jakob's avatar
Wenzel Jakob committed
131
132
133
134
135
136
        .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
137
        .def("get", [](ElementList &el) {
Wenzel Jakob's avatar
Wenzel Jakob committed
138
139
140
141
142
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
143
144

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

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

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

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

173
    // Issue #328: first member in a class can't be used in operators
174
175
176
    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);
177
178
    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);
179
180
181
    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; });
182
183
184
185
186

    // Issue 389: r_v_p::move should fall-through to copy on non-movable objects
    class MoveIssue1 {
    public:
        MoveIssue1(int v) : v{v} {}
187
        MoveIssue1(const MoveIssue1 &c) { v = c.v; }
188
189
190
191
192
193
194
195
196
197
198
199
200
        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);
201

202
    // Issues 392/397: overridding reference-returning functions
203
204
    class OverrideTest {
    public:
205
206
        struct A { std::string value = "hi"; };
        std::string v;
207
        A a;
208
209
210
        explicit OverrideTest(const std::string &v) : v{v} {}
        virtual std::string str_value() { return v; }
        virtual std::string &str_ref() { return v; }
211
212
213
214
215
216
        virtual A A_value() { return a; }
        virtual A &A_ref() { return a; }
    };
    class PyOverrideTest : public OverrideTest {
    public:
        using OverrideTest::OverrideTest;
217
        std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); }
218
219
        // 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:
220
221
222
223
224
225
226
227
//      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(); }

228
229
230
231
232
233
        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")
234
235
236
        .def(py::init<const std::string &>())
        .def("str_value", &OverrideTest::str_value)
//      .def("str_ref", &OverrideTest::str_ref)
237
238
        .def("A_value", &OverrideTest::A_value)
        .def("A_ref", &OverrideTest::A_ref);
239

240
241
242
243
244
245
246
247
248
249
    /// 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; });
250
251
252
253
254

    // 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); });
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
293
294
295

    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;
    });
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

    /// 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);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

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

336
337
338
    /// 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())); });
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358

    /// 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);
359

360
361
362
363
364
    py::dict d;
    std::string bar = "bar";
    d["str"] = bar;
    d["num"] = 3.7;

365
366
367
368
369
370
371
372
373
    /// 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
374
}
375

376
// MSVC workaround: trying to use a lambda here crashes MSVC
377
test_initializer issues(&init_issues);