blob: f26f6c33fe3c55d3be332a811650d490f150e2e5 [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
Lunderbergc7fcde72017-02-22 14:00:59 -050074class AbstractBase {
75public:
76 virtual unsigned int func() = 0;
77};
78
79void func_accepting_func_accepting_base(std::function<double(AbstractBase&)>) { }
80
81struct MovableObject {
82 bool valid = true;
83
84 MovableObject() = default;
85 MovableObject(const MovableObject &) = default;
86 MovableObject &operator=(const MovableObject &) = default;
87 MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; }
88 MovableObject &operator=(MovableObject &&o) {
89 valid = o.valid;
90 o.valid = false;
91 return *this;
92 }
93};
94
Jason Rhinelander52f4be82016-09-03 14:54:22 -040095test_initializer callbacks([](py::module &m) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +020096 m.def("test_callback1", &test_callback1);
97 m.def("test_callback2", &test_callback2);
98 m.def("test_callback3", &test_callback3);
Wenzel Jakob281aa0e2015-07-30 15:29:00 +020099 m.def("test_callback4", &test_callback4);
Brad Harmon835fc062016-06-16 13:19:15 -0500100 m.def("test_callback5", &test_callback5);
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200101
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200102 // Test keyword args and generalized unpacking
103 m.def("test_tuple_unpacking", [](py::function f) {
104 auto t1 = py::make_tuple(2, 3);
105 auto t2 = py::make_tuple(5, 6);
106 return f("positional", 1, *t1, 4, *t2);
107 });
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200108
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200109 m.def("test_dict_unpacking", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200110 auto d1 = py::dict("key"_a="value", "a"_a=1);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200111 auto d2 = py::dict();
Dean Moldovan15a112f2016-08-30 12:05:53 +0200112 auto d3 = py::dict("b"_a=2);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200113 return f("positional", 1, **d1, **d2, **d3);
114 });
115
116 m.def("test_keyword_args", [](py::function f) {
117 return f("x"_a=10, "y"_a=20);
118 });
119
120 m.def("test_unpacking_and_keywords1", [](py::function f) {
121 auto args = py::make_tuple(2);
Dean Moldovan15a112f2016-08-30 12:05:53 +0200122 auto kwargs = py::dict("d"_a=4);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200123 return f(1, *args, "c"_a=3, **kwargs);
124 });
125
126 m.def("test_unpacking_and_keywords2", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200127 auto kwargs1 = py::dict("a"_a=1);
128 auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200129 return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
130 "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
131 });
132
133 m.def("test_unpacking_error1", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200134 auto kwargs = py::dict("x"_a=3);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200135 return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
136 });
137
138 m.def("test_unpacking_error2", [](py::function f) {
Dean Moldovan15a112f2016-08-30 12:05:53 +0200139 auto kwargs = py::dict("x"_a=3);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200140 return f(**kwargs, "x"_a=1); // duplicate keyword after **
141 });
142
143 m.def("test_arg_conversion_error1", [](py::function f) {
Dean Moldovan83e328f2017-06-09 00:44:49 +0200144 f(234, UnregisteredType(), "kw"_a=567);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200145 });
146
147 m.def("test_arg_conversion_error2", [](py::function f) {
Dean Moldovan83e328f2017-06-09 00:44:49 +0200148 f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
Dean Moldovanc743e1b2016-08-29 03:05:42 +0200149 });
150
151 /* Test cleanup of lambda closure */
Wenzel Jakobfe342412016-09-06 13:02:29 +0900152 m.def("test_cleanup", []() -> std::function<void(void)> {
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200153 Payload p;
154
155 return [p]() {
156 /* p should be cleaned up when the returned function is garbage collected */
Wenzel Jakobcecb5772017-02-26 23:15:39 +0100157 (void) p;
Wenzel Jakob19208fe2015-10-13 17:37:25 +0200158 };
159 });
Wenzel Jakob954b7932016-07-10 10:13:18 +0200160
161 /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
162 m.def("dummy_function", &dummy_function);
163 m.def("dummy_function2", &dummy_function2);
Dean Moldovan665e8802016-08-12 22:28:31 +0200164 m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false);
Wenzel Jakob954b7932016-07-10 10:13:18 +0200165 m.def("test_dummy_function", &test_dummy_function);
Jason Rhinelander3f589372016-08-07 13:05:26 -0400166 // Export the payload constructor statistics for testing purposes:
167 m.def("payload_cstats", &ConstructorStats::get<Payload>);
Lunderbergc7fcde72017-02-22 14:00:59 -0500168
169 m.def("func_accepting_func_accepting_base",
170 func_accepting_func_accepting_base);
171
172 py::class_<MovableObject>(m, "MovableObject");
173
174 m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) {
175 auto x = MovableObject();
176 f(x); // lvalue reference shouldn't move out object
177 return x.valid; // must still return `true`
178 });
Jason Rhinelandera01b6b82017-04-24 12:29:42 -0400179
180 struct CppBoundMethodTest {};
181 py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest")
182 .def(py::init<>())
183 .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; });
Jason Rhinelander52f4be82016-09-03 14:54:22 -0400184});