test_issues.cpp 6.8 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
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);

17
18
19
20
21
22
#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) };

23
24
25
void init_issues(py::module &m) {
    py::module m2 = m.def_submodule("issues");

Wenzel Jakob's avatar
Wenzel Jakob committed
26
27
28
29
30
31
#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");
32
    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
Wenzel Jakob's avatar
Wenzel Jakob committed
33
34
35
        py::return_value_policy::reference);
#endif

36
37
    // #137: const char* isn't handled properly
    m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
38
39
40

    // #150: char bindings broken
    m2.def("print_char", [](char c) { std::cout << c << std::endl; });
41
42

    // #159: virtual function dispatch has problems with similar-named functions
Wenzel Jakob's avatar
Wenzel Jakob committed
43
44
45
    struct Base { virtual void dispatch(void) const {
        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
    }; };
Wenzel Jakob's avatar
Wenzel Jakob committed
46
47
48
49
50
51
52

    struct DispatchIssue : Base {
        virtual void dispatch(void) const {
            PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
        }
    };

53
    py::class_<Base, std::unique_ptr<Base>, DispatchIssue>(m2, "DispatchIssue")
54
        .def(py::init<>())
55
56
        .def("dispatch", &Base::dispatch);

Wenzel Jakob's avatar
Wenzel Jakob committed
57
58
59
    m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
60
61

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

    // #171: Can't return reference wrappers (or STL datastructures containing them)
66
    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4){
67
68
        Placeholder *p1 = new Placeholder{1};
        Placeholder *p2 = new Placeholder{2};
69
        Placeholder *p3 = new Placeholder{3};
70
71
72
73
        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));
74
        v.push_back(p4);
75
76
        return v;
    });
77
78
79
80
81

    // #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
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

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

    py::class_<ElementA, std::shared_ptr<ElementA>>(m2, "ElementA", py::base<ElementBase>())
        .def(py::init<int>())
        .def("value", &ElementA::value);

    py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
        .def(py::init<>())
        .def("add", &ElementList::add)
        .def("get", [](ElementList &el){
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
111
112
113

    // (no id): should not be able to pass 'None' to a reference argument
    m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; });
114
115
116
117

    // (no id): don't cast doubles to ints
    m2.def("expect_float", [](float f) { return f; });
    m2.def("expect_int", [](int i) { return i; });
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

    // (no id): don't invoke Python dispatch code when instantiating C++
    // classes that were not extended on the Python side
    struct A {
        virtual ~A() {}
        virtual void f() { std::cout << "A.f()" << std::endl; }
    };

    struct PyA : A {
        PyA() { std::cout << "PyA.PyA()" << std::endl; }

        void f() override {
            std::cout << "PyA.f()" << std::endl;
            PYBIND11_OVERLOAD(void, A, f);
        }
    };

    auto call_f = [](A *a) { a->f(); };

Wenzel Jakob's avatar
Wenzel Jakob committed
137
138
139
    pybind11::class_<A, std::unique_ptr<A>, PyA>(m2, "A")
        .def(py::init<>())
        .def("f", &A::f);
140

Wenzel Jakob's avatar
Wenzel Jakob committed
141
    m2.def("call_f", call_f);
142
143
144
145

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

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

168
    // Issue #328: first member in a class can't be used in operators
169
170
171
    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);
172
173
174
175
176
    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);
    m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
    m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
    m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
177
}