blob: 41110087c22e5b1fd9a27e4bf0229b791adc6d62 [file] [log] [blame]
Wenzel Jakob38bd7112015-07-05 20:05:44 +02001/*
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002 tests/test_callbacks.cpp -- callbacks
Wenzel Jakob38bd7112015-07-05 20:05:44 +02003
Wenzel Jakob8cb6cb32016-04-17 20:21:41 +02004 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
Wenzel Jakob38bd7112015-07-05 20:05:44 +02005
6 All rights reserved. Use of this source code is governed by a
7 BSD-style license that can be found in the LICENSE file.
8*/
9
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020010#include "pybind11_tests.h"
11#include "constructor_stats.h"
Wenzel Jakob8f4eb002015-10-15 18:13:33 +020012#include <pybind11/functional.h>
Wenzel Jakob38bd7112015-07-05 20:05:44 +020013
14
Dean Moldovan665e8802016-08-12 22:28:31 +020015py::object test_callback1(py::object func) {
16 return func();
Wenzel Jakob38bd7112015-07-05 20:05:44 +020017}
18
Dean Moldovan665e8802016-08-12 22:28:31 +020019py::tuple test_callback2(py::object func) {
20 return func("Hello", 'x', true, 5);
Wenzel Jakob38bd7112015-07-05 20:05:44 +020021}
22
Dean Moldovan665e8802016-08-12 22:28:31 +020023std::string test_callback3(const std::function<int(int)> &func) {
24 return "func(43) = " + std::to_string(func(43));
Wenzel Jakob281aa0e2015-07-30 15:29:00 +020025}
26
Wenzel Jakoba2f6fde2015-10-01 16:46:03 +020027std::function<int(int)> test_callback4() {
Wenzel Jakob281aa0e2015-07-30 15:29:00 +020028 return [](int i) { return i+1; };
29}
30
Brad Harmon835fc062016-06-16 13:19:15 -050031py::cpp_function test_callback5() {
32 return py::cpp_function([](int i) { return i+1; },
33 py::arg("number"));
34}
35
Wenzel Jakob954b7932016-07-10 10:13:18 +020036int dummy_function(int i) { return i + 1; }
37int dummy_function2(int i, int j) { return i + j; }
Dean Moldovan665e8802016-08-12 22:28:31 +020038std::function<int(int)> roundtrip(std::function<int(int)> f, bool expect_none = false) {
39 if (expect_none && f) {
40 throw std::runtime_error("Expected None to be converted to empty std::function");
41 }
Wenzel Jakob954b7932016-07-10 10:13:18 +020042 return f;
43}
44
Dean Moldovan665e8802016-08-12 22:28:31 +020045std::string test_dummy_function(const std::function<int(int)> &f) {
Wenzel Jakob954b7932016-07-10 10:13:18 +020046 using fn_type = int (*)(int);
47 auto result = f.target<fn_type>();
48 if (!result) {
Wenzel Jakob954b7932016-07-10 10:13:18 +020049 auto r = f(1);
Dean Moldovan665e8802016-08-12 22:28:31 +020050 return "can't convert to function pointer: eval(1) = " + std::to_string(r);
Wenzel Jakob954b7932016-07-10 10:13:18 +020051 } else if (*result == dummy_function) {
Wenzel Jakob954b7932016-07-10 10:13:18 +020052 auto r = (*result)(1);
Dean Moldovan665e8802016-08-12 22:28:31 +020053 return "matches dummy_function: eval(1) = " + std::to_string(r);
Wenzel Jakob954b7932016-07-10 10:13:18 +020054 } else {
Dean Moldovan665e8802016-08-12 22:28:31 +020055 return "argument does NOT match dummy_function. This should never happen!";
Wenzel Jakob954b7932016-07-10 10:13:18 +020056 }
57}
58
Jason Rhinelander3f589372016-08-07 13:05:26 -040059struct Payload {
60 Payload() {
61 print_default_created(this);
62 }
63 ~Payload() {
64 print_destroyed(this);
65 }
66 Payload(const Payload &) {
67 print_copy_created(this);
68 }
69 Payload(Payload &&) {
70 print_move_created(this);
71 }
72};
73
Dean Moldovanc743e1b2016-08-29 03:05:42 +020074/// Something to trigger a conversion error
75struct Unregistered {};
76
Lunderbergc7fcde72017-02-22 14:00:59 -050077class AbstractBase {
78public:
79 virtual unsigned int func() = 0;
80};
81
82void func_accepting_func_accepting_base(std::function<double(AbstractBase&)>) { }
83
84struct MovableObject {
85 bool valid = true;
86
87 MovableObject() = default;
88 MovableObject(const MovableObject &) = default;
89 MovableObject &operator=(const MovableObject &) = default;
90 MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
91 MovableObject &operator=(MovableObject &&o) {
92 valid = o.valid;
93 o.valid = false;
94 return *this;
95 }
96};
97
Jason Rhinelander52f4be82016-09-03 14:54:22 -040098test_initializer callbacks([](py::module &m) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +020099 m.def("test_callback1", &test_callback1);
100 m.def("test_callback2", &test_callback2);
101 m.def("test_callback3", &test_callback3);
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200102 m.def("test_callback4", &test_callback4);
Brad Harmon835fc062016-06-16 13:19:15 -0500103 m.def("test_callback5", &test_callback5);
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200104
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200105 // Test keyword args and generalized unpacking
106 m.def("test_tuple_unpacking", [](py::function f) {
107 auto t1 = py::make_tuple(2, 3);
108 auto t2 = py::make_tuple(5, 6);
109 return f("positional", 1, *t1, 4, *t2);
110 });
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200111
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200112 m.def("test_dict_unpacking", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200113 auto d1 = py::dict("key"_a="value", "a"_a=1);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200114 auto d2 = py::dict();
Dean Moldovan15a112f2016-08-30 12:05:53 +0200115 auto d3 = py::dict("b"_a=2);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200116 return f("positional", 1, **d1, **d2, **d3);
117 });
118
119 m.def("test_keyword_args", [](py::function f) {
120 return f("x"_a=10, "y"_a=20);
121 });
122
123 m.def("test_unpacking_and_keywords1", [](py::function f) {
124 auto args = py::make_tuple(2);
Dean Moldovan15a112f2016-08-30 12:05:53 +0200125 auto kwargs = py::dict("d"_a=4);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200126 return f(1, *args, "c"_a=3, **kwargs);
127 });
128
129 m.def("test_unpacking_and_keywords2", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200130 auto kwargs1 = py::dict("a"_a=1);
131 auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200132 return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
133 "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
134 });
135
136 m.def("test_unpacking_error1", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200137 auto kwargs = py::dict("x"_a=3);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200138 return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
139 });
140
141 m.def("test_unpacking_error2", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200142 auto kwargs = py::dict("x"_a=3);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200143 return f(**kwargs, "x"_a=1); // duplicate keyword after **
144 });
145
146 m.def("test_arg_conversion_error1", [](py::function f) {
147 f(234, Unregistered(), "kw"_a=567);
148 });
149
150 m.def("test_arg_conversion_error2", [](py::function f) {
151 f(234, "expected_name"_a=Unregistered(), "kw"_a=567);
152 });
153
154 /* Test cleanup of lambda closure */
Wenzel Jakobfe342412016-09-06 13:02:29 +0900155 m.def("test_cleanup", []() -> std::function<void(void)> {
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200156 Payload p;
157
158 return [p]() {
159 /* p should be cleaned up when the returned function is garbage collected */
Wenzel Jakobcecb5772017-02-26 23:15:39 +0100160 (void) p;
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200161 };
162 });
Wenzel Jakob954b7932016-07-10 10:13:18 +0200163
164 /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
165 m.def("dummy_function", &dummy_function);
166 m.def("dummy_function2", &dummy_function2);
Dean Moldovan665e8802016-08-12 22:28:31 +0200167 m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false);
Wenzel Jakob954b7932016-07-10 10:13:18 +0200168 m.def("test_dummy_function", &test_dummy_function);
Jason Rhinelander3f589372016-08-07 13:05:26 -0400169 // Export the payload constructor statistics for testing purposes:
170 m.def("payload_cstats", &ConstructorStats::get<Payload>);
Lunderbergc7fcde72017-02-22 14:00:59 -0500171
172 m.def("func_accepting_func_accepting_base",
173 func_accepting_func_accepting_base);
174
175 py::class_<MovableObject>(m, "MovableObject");
176
177 m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
178 auto x = MovableObject();
179 f(x); // lvalue reference shouldn't move out object
180 return x.valid; // must still return `true`
181 });
Jason Rhinelandera01b6b82017-04-24 12:29:42 -0400182
183 struct CppBoundMethodTest {};
184 py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
185 .def(py::init<>())
186 .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
Jason Rhinelander52f4be82016-09-03 14:54:22 -0400187});