this repo has no description
at trunk 310 lines 11 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "Python.h" 3#include "gtest/gtest.h" 4 5#include "capi-fixture.h" 6#include "capi-testing.h" 7 8namespace py { 9namespace testing { 10 11using PyCFunctionExtensionApiTest = ExtensionApi; 12 13PyObject* getPyCFunctionDunderModule(PyObject* function) { 14 PyObject* real_function = function; 15 // Work around PyRo behavior. 16 if (PyMethod_Check(function)) { 17 real_function = PyMethod_Function(function); 18 } 19 return PyObject_GetAttrString(real_function, "__module__"); 20} 21 22TEST_F(PyCFunctionExtensionApiTest, CheckWithNonFunctionReturnsFalse) { 23 EXPECT_FALSE(PyCFunction_Check(Py_True)); 24} 25 26TEST_F(PyCFunctionExtensionApiTest, CheckWithNonExtensionFunctionReturnsFalse) { 27 PyRun_SimpleString("def func(): pass"); 28 PyObjectPtr func(mainModuleGet("func")); 29 EXPECT_FALSE(PyCFunction_Check(func)); 30} 31 32TEST_F(PyCFunctionExtensionApiTest, CheckWithBoundMethodReturnsFalse) { 33 PyRun_SimpleString(R"( 34class C: 35 def foo(self): 36 pass 37method = C.foo 38)"); 39 PyObjectPtr method(mainModuleGet("method")); 40 EXPECT_FALSE(PyCFunction_Check(method)); 41} 42 43TEST_F(PyCFunctionExtensionApiTest, 44 GetFunctionWithNonCFunctionRaisesBadInternalCall) { 45 PyObjectPtr value(PyLong_FromLong(42)); 46 EXPECT_EQ(PyCFunction_GetFunction(value), nullptr); 47 EXPECT_NE(PyErr_Occurred(), nullptr); 48 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 49} 50 51TEST_F(PyCFunctionExtensionApiTest, 52 GetSelfWithNonCFunctionRaisesBadInternalCall) { 53 PyObjectPtr value(PyLong_FromLong(42)); 54 EXPECT_EQ(PyCFunction_GetSelf(value), nullptr); 55 EXPECT_NE(PyErr_Occurred(), nullptr); 56 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 57} 58 59TEST_F(PyCFunctionExtensionApiTest, GET_SELFReturnsSelf) { 60 PyObjectPtr self_value(PyUnicode_FromString("baz")); 61 binaryfunc meth = [](PyObject* self, PyObject* arg) { 62 EXPECT_EQ(arg, nullptr); 63 Py_INCREF(self); 64 return self; 65 }; 66 static PyMethodDef func_def = {"foo", meth, METH_NOARGS}; 67 PyObjectPtr func(PyCFunction_New(&func_def, self_value)); 68 ASSERT_NE(func, nullptr); 69 PyObjectPtr result(_PyObject_CallNoArg(func)); 70 EXPECT_EQ(result, self_value); 71 ASSERT_EQ(PyErr_Occurred(), nullptr); 72 73 EXPECT_TRUE(PyCFunction_Check(func)); 74 EXPECT_EQ(PyCFunction_GET_SELF(func.get()), self_value.get()); 75} 76 77TEST_F(PyCFunctionExtensionApiTest, NewReturnsCallable) { 78 PyObjectPtr self_value(PyUnicode_FromString("baz")); 79 binaryfunc meth = [](PyObject* self, PyObject* arg) { 80 EXPECT_EQ(arg, nullptr); 81 Py_INCREF(self); 82 return self; 83 }; 84 static PyMethodDef func_def = {"foo", meth, METH_NOARGS}; 85 PyObjectPtr func(PyCFunction_New(&func_def, self_value)); 86 ASSERT_NE(func, nullptr); 87 PyObjectPtr result(_PyObject_CallNoArg(func)); 88 EXPECT_EQ(result, self_value); 89 ASSERT_EQ(PyErr_Occurred(), nullptr); 90 PyObjectPtr dunder_module(getPyCFunctionDunderModule(func)); 91 EXPECT_EQ(dunder_module, Py_None); 92 93 EXPECT_TRUE(PyCFunction_Check(func)); 94 EXPECT_EQ(PyCFunction_GetFunction(func), meth); 95 EXPECT_EQ(PyCFunction_GetSelf(func), self_value.get()); 96} 97 98TEST_F(PyCFunctionExtensionApiTest, NewExWithModuleReturnsCallable) { 99 PyObjectPtr self_value(PyUnicode_FromString("foo")); 100 PyObjectPtr module_name(PyUnicode_FromString("bar")); 101 binaryfunc meth = [](PyObject* self, PyObject* arg) { 102 EXPECT_EQ(arg, nullptr); 103 Py_INCREF(self); 104 return self; 105 }; 106 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 107 PyObjectPtr func(PyCFunction_NewEx(&foo_func, self_value, module_name)); 108 ASSERT_NE(func, nullptr); 109 PyObjectPtr noargs(PyTuple_New(0)); 110 PyObjectPtr result(PyObject_Call(func, noargs, nullptr)); 111 EXPECT_EQ(result, self_value); 112 ASSERT_EQ(PyErr_Occurred(), nullptr); 113 PyObjectPtr dunder_module(getPyCFunctionDunderModule(func)); 114 EXPECT_EQ(dunder_module, module_name); 115 116 EXPECT_TRUE(PyCFunction_Check(func)); 117 EXPECT_EQ(PyCFunction_GetFunction(func), meth); 118 EXPECT_EQ(PyCFunction_GetSelf(func), self_value.get()); 119} 120 121TEST_F(PyCFunctionExtensionApiTest, NewExWithNullSelfReturnsCallable) { 122 binaryfunc meth = [](PyObject* self, PyObject* arg) { 123 EXPECT_EQ(self, nullptr); 124 EXPECT_EQ(arg, nullptr); 125 Py_INCREF(Py_None); 126 return Py_None; 127 }; 128 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 129 PyObjectPtr func( 130 PyCFunction_NewEx(&foo_func, /*self=*/nullptr, /*module=*/nullptr)); 131 ASSERT_NE(func, nullptr); 132 PyObjectPtr noargs(PyTuple_New(0)); 133 PyObjectPtr result(PyObject_Call(func, noargs, nullptr)); 134 EXPECT_EQ(result, Py_None); 135 ASSERT_EQ(PyErr_Occurred(), nullptr); 136 PyObjectPtr dunder_module(getPyCFunctionDunderModule(func)); 137 EXPECT_EQ(dunder_module, Py_None); 138 139 EXPECT_TRUE(PyCFunction_Check(func)); 140 EXPECT_EQ(PyCFunction_GetFunction(func), meth); 141 EXPECT_EQ(PyCFunction_GetSelf(func), nullptr); 142 EXPECT_EQ(PyErr_Occurred(), nullptr); 143} 144 145TEST_F(PyCFunctionExtensionApiTest, NewExResultDoesNotBindSelfInClass) { 146 PyRun_SimpleString(R"( 147class C: 148 pass 149instance = C() 150)"); 151 PyObjectPtr self_value(PyUnicode_FromString("foo")); 152 binaryfunc meth = [](PyObject* self, PyObject* arg) { 153 EXPECT_EQ(arg, nullptr); 154 Py_INCREF(self); 155 return self; 156 }; 157 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS}; 158 PyObjectPtr func( 159 PyCFunction_NewEx(&foo_func, self_value, /*module=*/nullptr)); 160 ASSERT_NE(func, nullptr); 161 PyObjectPtr c(mainModuleGet("C")); 162 PyObjectPtr instance(mainModuleGet("instance")); 163 PyObject_SetAttrString(c, "foo", func); 164 PyObjectPtr result(PyObject_CallMethod(instance, "foo", "")); 165 EXPECT_NE(result, c); 166 EXPECT_EQ(result, self_value); 167} 168 169TEST_F(PyCFunctionExtensionApiTest, NewExWithMethNoArgsCallsFunction) { 170 PyCFunction foo_func = [](PyObject* self, PyObject* args) { 171 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 172 EXPECT_EQ(args, nullptr); 173 return PyLong_FromLong(-7); 174 }; 175 PyMethodDef def = { 176 "foo", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(foo_func)), 177 METH_NOARGS}; 178 PyObjectPtr self(PyUnicode_FromString("self")); 179 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 180 181 PyObjectPtr result(_PyObject_CallNoArg(func)); 182 ASSERT_TRUE(isLongEqualsLong(result, -7)); 183 EXPECT_EQ(PyErr_Occurred(), nullptr); 184} 185 186TEST_F(PyCFunctionExtensionApiTest, NewExWithMethOCallsFunction) { 187 PyCFunction foo_func = [](PyObject* self, PyObject* arg) { 188 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 189 EXPECT_TRUE(isLongEqualsLong(arg, 42)); 190 return PyLong_FromLong(1); 191 }; 192 PyMethodDef def = {"foo", foo_func, METH_O}; 193 PyObjectPtr self(PyUnicode_FromString("self")); 194 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 195 PyObjectPtr arg(PyLong_FromLong(42)); 196 197 PyObject* args[1] = {arg.get()}; 198 PyObjectPtr result(_PyObject_FastCallDict(func, args, 1, nullptr)); 199 ASSERT_TRUE(isLongEqualsLong(result, 1)); 200 EXPECT_EQ(PyErr_Occurred(), nullptr); 201} 202 203TEST_F(PyCFunctionExtensionApiTest, NewExWithMethVarArgsCallsFunction) { 204 PyCFunction foo_func = [](PyObject* self, PyObject* args) { 205 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 206 EXPECT_TRUE(PyTuple_Check(args)); 207 EXPECT_EQ(PyTuple_Size(args), 2); 208 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(args, 0), -14)); 209 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(args, 1), 15)); 210 return PyLong_FromLong(22); 211 }; 212 PyMethodDef def = {"foo", foo_func, METH_VARARGS}; 213 PyObjectPtr self(PyUnicode_FromString("self")); 214 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 215 PyObjectPtr arg0(PyLong_FromLong(-14)); 216 PyObjectPtr arg1(PyLong_FromLong(15)); 217 PyObjectPtr args(PyTuple_Pack(2, arg0.get(), arg1.get())); 218 219 PyObjectPtr result(PyObject_Call(func, args, nullptr)); 220 ASSERT_TRUE(isLongEqualsLong(result, 22)); 221 EXPECT_EQ(PyErr_Occurred(), nullptr); 222} 223 224TEST_F(PyCFunctionExtensionApiTest, NewExWithVarArgsAndKeywordsCallsFunction) { 225 PyCFunctionWithKeywords foo_func = [](PyObject* self, PyObject* args, 226 PyObject* kwargs) -> PyObject* { 227 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 228 EXPECT_TRUE(PyTuple_Check(args)); 229 EXPECT_EQ(PyTuple_Size(args), 2); 230 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(args, 0), -111)); 231 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(args, 1), 222)); 232 EXPECT_TRUE(PyDict_Check(kwargs)); 233 EXPECT_EQ(PyDict_Size(kwargs), 1); 234 EXPECT_TRUE(isLongEqualsLong(PyDict_GetItemString(kwargs, "keyword"), 333)); 235 return PyLong_FromLong(876); 236 }; 237 PyMethodDef def = { 238 "foo", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(foo_func)), 239 METH_VARARGS | METH_KEYWORDS}; 240 PyObjectPtr self(PyUnicode_FromString("self")); 241 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 242 243 PyObjectPtr arg0(PyLong_FromLong(-111)); 244 PyObjectPtr arg1(PyLong_FromLong(222)); 245 PyObjectPtr args(PyTuple_Pack(2, arg0.get(), arg1.get())); 246 PyObjectPtr kwargs(PyDict_New()); 247 PyObjectPtr value(PyLong_FromLong(333)); 248 PyDict_SetItemString(kwargs, "keyword", value); 249 PyObjectPtr result(PyObject_Call(func, args, kwargs)); 250 ASSERT_TRUE(isLongEqualsLong(result, 876)); 251 EXPECT_EQ(PyErr_Occurred(), nullptr); 252} 253 254TEST_F(PyCFunctionExtensionApiTest, NewExWithMethFastCallCallsFunction) { 255 _PyCFunctionFast foo_func = [](PyObject* self, PyObject* const* args, 256 Py_ssize_t num_args) -> PyObject* { 257 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 258 EXPECT_EQ(num_args, 3); 259 EXPECT_TRUE(isLongEqualsLong(args[0], 17)); 260 EXPECT_TRUE(isLongEqualsLong(args[1], -8)); 261 EXPECT_TRUE(isLongEqualsLong(args[2], 99)); 262 return PyLong_FromLong(4444); 263 }; 264 PyMethodDef def = { 265 "foo", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(foo_func)), 266 METH_FASTCALL}; 267 PyObjectPtr self(PyUnicode_FromString("self")); 268 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 269 270 PyObjectPtr arg0(PyLong_FromLong(17)); 271 PyObjectPtr arg1(PyLong_FromLong(-8)); 272 PyObjectPtr arg2(PyLong_FromLong(99)); 273 PyObjectPtr args(PyTuple_Pack(3, arg0.get(), arg1.get(), arg2.get())); 274 PyObjectPtr result(PyObject_Call(func, args, nullptr)); 275 ASSERT_TRUE(isLongEqualsLong(result, 4444)); 276 EXPECT_EQ(PyErr_Occurred(), nullptr); 277} 278 279TEST_F(PyCFunctionExtensionApiTest, 280 NewExWithMethFastCallAndKeywordsCallsFunction) { 281 _PyCFunctionFastWithKeywords foo_func = 282 [](PyObject* self, PyObject* const* args, Py_ssize_t num_args, 283 PyObject* kwnames) -> PyObject* { 284 EXPECT_TRUE(isUnicodeEqualsCStr(self, "self")); 285 EXPECT_EQ(num_args, 1); 286 EXPECT_TRUE(isLongEqualsLong(args[0], 42)); 287 EXPECT_TRUE(isLongEqualsLong(args[1], 30)); 288 EXPECT_TRUE(PyTuple_Check(kwnames)); 289 EXPECT_EQ(PyTuple_Size(kwnames), 1); 290 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 0), "keyword")); 291 return PyLong_FromLong(333); 292 }; 293 PyMethodDef def = { 294 "foo", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(foo_func)), 295 METH_FASTCALL | METH_KEYWORDS}; 296 PyObjectPtr self(PyUnicode_FromString("self")); 297 PyObjectPtr func(PyCFunction_NewEx(&def, self, nullptr)); 298 299 PyObjectPtr arg(PyLong_FromLong(42)); 300 PyObjectPtr args(PyTuple_Pack(1, arg.get())); 301 PyObjectPtr kwargs(PyDict_New()); 302 PyObjectPtr value(PyLong_FromLong(30)); 303 PyDict_SetItemString(kwargs, "keyword", value); 304 PyObjectPtr result(PyObject_Call(func, args, kwargs)); 305 ASSERT_TRUE(isLongEqualsLong(result, 333)); 306 EXPECT_EQ(PyErr_Occurred(), nullptr); 307} 308 309} // namespace testing 310} // namespace py