test_callbacks.cpp revision 12391:ceeca8b41e4b
1/* 2 tests/test_callbacks.cpp -- callbacks 3 4 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 5 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 10#include "pybind11_tests.h" 11#include "constructor_stats.h" 12#include <pybind11/functional.h> 13 14 15int dummy_function(int i) { return i + 1; } 16 17TEST_SUBMODULE(callbacks, m) { 18 // test_callbacks, test_function_signatures 19 m.def("test_callback1", [](py::object func) { return func(); }); 20 m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); }); 21 m.def("test_callback3", [](const std::function<int(int)> &func) { 22 return "func(43) = " + std::to_string(func(43)); }); 23 m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; }); 24 m.def("test_callback5", []() { 25 return py::cpp_function([](int i) { return i+1; }, py::arg("number")); 26 }); 27 28 // test_keyword_args_and_generalized_unpacking 29 m.def("test_tuple_unpacking", [](py::function f) { 30 auto t1 = py::make_tuple(2, 3); 31 auto t2 = py::make_tuple(5, 6); 32 return f("positional", 1, *t1, 4, *t2); 33 }); 34 35 m.def("test_dict_unpacking", [](py::function f) { 36 auto d1 = py::dict("key"_a="value", "a"_a=1); 37 auto d2 = py::dict(); 38 auto d3 = py::dict("b"_a=2); 39 return f("positional", 1, **d1, **d2, **d3); 40 }); 41 42 m.def("test_keyword_args", [](py::function f) { 43 return f("x"_a=10, "y"_a=20); 44 }); 45 46 m.def("test_unpacking_and_keywords1", [](py::function f) { 47 auto args = py::make_tuple(2); 48 auto kwargs = py::dict("d"_a=4); 49 return f(1, *args, "c"_a=3, **kwargs); 50 }); 51 52 m.def("test_unpacking_and_keywords2", [](py::function f) { 53 auto kwargs1 = py::dict("a"_a=1); 54 auto kwargs2 = py::dict("c"_a=3, "d"_a=4); 55 return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, 56 "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); 57 }); 58 59 m.def("test_unpacking_error1", [](py::function f) { 60 auto kwargs = py::dict("x"_a=3); 61 return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword 62 }); 63 64 m.def("test_unpacking_error2", [](py::function f) { 65 auto kwargs = py::dict("x"_a=3); 66 return f(**kwargs, "x"_a=1); // duplicate keyword after ** 67 }); 68 69 m.def("test_arg_conversion_error1", [](py::function f) { 70 f(234, UnregisteredType(), "kw"_a=567); 71 }); 72 73 m.def("test_arg_conversion_error2", [](py::function f) { 74 f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); 75 }); 76 77 // test_lambda_closure_cleanup 78 struct Payload { 79 Payload() { print_default_created(this); } 80 ~Payload() { print_destroyed(this); } 81 Payload(const Payload &) { print_copy_created(this); } 82 Payload(Payload &&) { print_move_created(this); } 83 }; 84 // Export the payload constructor statistics for testing purposes: 85 m.def("payload_cstats", &ConstructorStats::get<Payload>); 86 /* Test cleanup of lambda closure */ 87 m.def("test_cleanup", []() -> std::function<void(void)> { 88 Payload p; 89 90 return [p]() { 91 /* p should be cleaned up when the returned function is garbage collected */ 92 (void) p; 93 }; 94 }); 95 96 // test_cpp_function_roundtrip 97 /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ 98 m.def("dummy_function", &dummy_function); 99 m.def("dummy_function2", [](int i, int j) { return i + j; }); 100 m.def("roundtrip", [](std::function<int(int)> f, bool expect_none = false) { 101 if (expect_none && f) 102 throw std::runtime_error("Expected None to be converted to empty std::function"); 103 return f; 104 }, py::arg("f"), py::arg("expect_none")=false); 105 m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string { 106 using fn_type = int (*)(int); 107 auto result = f.target<fn_type>(); 108 if (!result) { 109 auto r = f(1); 110 return "can't convert to function pointer: eval(1) = " + std::to_string(r); 111 } else if (*result == dummy_function) { 112 auto r = (*result)(1); 113 return "matches dummy_function: eval(1) = " + std::to_string(r); 114 } else { 115 return "argument does NOT match dummy_function. This should never happen!"; 116 } 117 }); 118 119 class AbstractBase { public: virtual unsigned int func() = 0; }; 120 m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { }); 121 122 struct MovableObject { 123 bool valid = true; 124 125 MovableObject() = default; 126 MovableObject(const MovableObject &) = default; 127 MovableObject &operator=(const MovableObject &) = default; 128 MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; } 129 MovableObject &operator=(MovableObject &&o) { 130 valid = o.valid; 131 o.valid = false; 132 return *this; 133 } 134 }; 135 py::class_<MovableObject>(m, "MovableObject"); 136 137 // test_movable_object 138 m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) { 139 auto x = MovableObject(); 140 f(x); // lvalue reference shouldn't move out object 141 return x.valid; // must still return `true` 142 }); 143 144 // test_bound_method_callback 145 struct CppBoundMethodTest {}; 146 py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest") 147 .def(py::init<>()) 148 .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); 149} 150