this repo has no description
at trunk 274 lines 9.6 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "Python.h" 3#include "gmock/gmock-matchers.h" 4#include "gtest/gtest.h" 5 6#include "capi-fixture.h" 7#include "capi-testing.h" 8 9namespace py { 10namespace testing { 11using CevalExtensionApiTest = ExtensionApi; 12 13TEST_F(CevalExtensionApiTest, EvalCodeWithNullGlobalsRaisesSystemError) { 14 PyObjectPtr empty_tuple(PyTuple_New(0)); 15 PyObjectPtr empty_bytes(PyBytes_FromString("")); 16 PyObjectPtr empty_str(PyUnicode_FromString("")); 17 PyCodeObject* code = PyCode_New( 18 0, 0, 0, 0, 0, empty_bytes, empty_tuple, empty_tuple, empty_tuple, 19 empty_tuple, empty_tuple, empty_str, empty_str, 0, empty_bytes); 20 EXPECT_EQ(PyErr_Occurred(), nullptr); 21 ASSERT_NE(code, nullptr); 22 PyObjectPtr locals(PyDict_New()); 23 EXPECT_EQ(PyEval_EvalCode(reinterpret_cast<PyObject*>(code), 24 /*globals=*/nullptr, locals), 25 nullptr); 26 ASSERT_NE(PyErr_Occurred(), nullptr); 27 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 28 Py_DECREF(code); 29} 30 31TEST_F(CevalExtensionApiTest, EvalCodeReturnsNonNull) { 32 PyCompilerFlags flags = _PyCompilerFlags_INIT; 33 PyArena* arena = PyArena_New(); 34 const char* filename = "<string>"; 35 struct _mod* node = PyParser_ASTFromString("a = 1 + 2", filename, 36 Py_file_input, &flags, arena); 37 ASSERT_NE(node, nullptr); 38 PyObjectPtr code(reinterpret_cast<PyObject*>( 39 PyAST_CompileEx(node, filename, &flags, 0, arena))); 40 ASSERT_NE(code, nullptr); 41 PyArena_Free(arena); 42 EXPECT_EQ(PyErr_Occurred(), nullptr); 43 PyRun_SimpleString(R"( 44module_dict = locals() 45)"); 46 PyObjectPtr module_dict(mainModuleGet("module_dict")); 47 PyObjectPtr locals(PyDict_New()); 48 EXPECT_NE(PyEval_EvalCode(code, /*globals=*/module_dict, locals), nullptr); 49 EXPECT_EQ(PyErr_Occurred(), nullptr); 50} 51 52TEST_F(CevalExtensionApiTest, EvalCodeWithDictGlobalsUpdatesDict) { 53 PyCompilerFlags flags = _PyCompilerFlags_INIT; 54 PyArena* arena = PyArena_New(); 55 const char* filename = "<string>"; 56 struct _mod* node = PyParser_ASTFromString("global a; a = 1 + 2", filename, 57 Py_file_input, &flags, arena); 58 ASSERT_NE(node, nullptr); 59 PyObjectPtr code(reinterpret_cast<PyObject*>( 60 PyAST_CompileEx(node, filename, &flags, 0, arena))); 61 ASSERT_NE(code, nullptr); 62 PyArena_Free(arena); 63 EXPECT_EQ(PyErr_Occurred(), nullptr); 64 PyObjectPtr globals(PyDict_New()); 65 PyObjectPtr locals(PyDict_New()); 66 EXPECT_NE(PyEval_EvalCode(code, globals, locals), nullptr); 67 EXPECT_EQ(PyErr_Occurred(), nullptr); 68 69 PyObjectPtr result(PyDict_GetItemString(globals, "a")); 70 EXPECT_TRUE(isLongEqualsLong(result, 3)); 71 EXPECT_EQ(PyDict_Size(locals), 0); 72} 73 74TEST_F(CevalExtensionApiTest, EvalCodeWithModuleDictAsGlobalsReturnsNonNull) { 75 PyCompilerFlags flags = _PyCompilerFlags_INIT; 76 PyArena* arena = PyArena_New(); 77 const char* filename = "<string>"; 78 struct _mod* node = 79 PyParser_ASTFromString(R"( 80global a 81a = 1 + 2 82)", 83 filename, Py_file_input, &flags, arena); 84 ASSERT_NE(node, nullptr); 85 PyObjectPtr code(reinterpret_cast<PyObject*>( 86 PyAST_CompileEx(node, filename, &flags, 0, arena))); 87 ASSERT_NE(code, nullptr); 88 PyArena_Free(arena); 89 EXPECT_EQ(PyErr_Occurred(), nullptr); 90 PyRun_SimpleString(R"( 91module_dict = locals() 92)"); 93 PyObjectPtr module_dict(mainModuleGet("module_dict")); 94 PyObjectPtr locals(PyDict_New()); 95 EXPECT_NE(PyEval_EvalCode(code, /*globals=*/module_dict, locals), nullptr); 96 EXPECT_EQ(PyErr_Occurred(), nullptr); 97 98 PyObjectPtr result(mainModuleGet("a")); 99 EXPECT_TRUE(PyLong_CheckExact(result)); 100 EXPECT_EQ(PyLong_AsDouble(result), 3.0); 101} 102 103TEST_F(CevalExtensionApiTest, 104 EvalCodeWithModuleDictAsGlobalsAndLocalsReturnsNonNull) { 105 PyCompilerFlags flags = _PyCompilerFlags_INIT; 106 PyArena* arena = PyArena_New(); 107 const char* filename = "<string>"; 108 struct _mod* node = PyParser_ASTFromString("a = 1 + 2", filename, 109 Py_file_input, &flags, arena); 110 ASSERT_NE(node, nullptr); 111 PyObjectPtr code(reinterpret_cast<PyObject*>( 112 PyAST_CompileEx(node, filename, &flags, 0, arena))); 113 ASSERT_NE(code, nullptr); 114 PyArena_Free(arena); 115 EXPECT_EQ(PyErr_Occurred(), nullptr); 116 PyRun_SimpleString(R"( 117module_dict = locals() 118)"); 119 PyObjectPtr module_dict(mainModuleGet("module_dict")); 120 EXPECT_NE( 121 PyEval_EvalCode(code, /*globals=*/module_dict, /*locals=*/module_dict), 122 nullptr); 123 EXPECT_EQ(PyErr_Occurred(), nullptr); 124 125 PyObjectPtr result(mainModuleGet("a")); 126 EXPECT_TRUE(PyLong_CheckExact(result)); 127 EXPECT_EQ(PyLong_AsDouble(result), 3.0); 128} 129 130TEST_F(CevalExtensionApiTest, GetBuiltinsReturnsMapping) { 131 PyObjectPtr builtins(PyEval_GetBuiltins()); // returns a borrowed reference 132 ASSERT_NE(builtins, nullptr); 133 Py_INCREF(builtins); 134 EXPECT_EQ(1, PyMapping_Check(builtins)); 135 // Check some sample builtins 136 EXPECT_EQ(1, PyMapping_HasKeyString(builtins, "int")); 137 EXPECT_EQ(1, PyMapping_HasKeyString(builtins, "compile")); 138} 139 140TEST_F(CevalExtensionApiTest, MergeCompilerFlagsReturnsTrue) { 141 PyCompilerFlags flags = _PyCompilerFlags_INIT; 142 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 143 EXPECT_NE(PyEval_MergeCompilerFlags(&flags), 0); 144 EXPECT_EQ(flags.cf_flags, CO_FUTURE_BARRY_AS_BDFL); 145} 146 147TEST_F(CevalExtensionApiTest, MergeCompilerFlagsReturnsFalse) { 148 PyCompilerFlags flags = _PyCompilerFlags_INIT; 149 EXPECT_EQ(PyEval_MergeCompilerFlags(&flags), 0); 150 EXPECT_EQ(flags.cf_flags, 0); 151} 152 153static PyObject* testMergeCompilerFlags(PyObject*, PyObject*) { 154 PyCompilerFlags flags = _PyCompilerFlags_INIT; 155 flags.cf_flags = 0xfba0000; 156 EXPECT_NE(PyEval_MergeCompilerFlags(&flags), 0); 157 return PyLong_FromLong(flags.cf_flags); 158} 159 160TEST_F(CevalExtensionApiTest, MergeCompilerFlagsMergesCodeFlags) { 161 static PyMethodDef methods[] = { 162 {"test_merge_compiler_flags", testMergeCompilerFlags, METH_NOARGS, ""}, 163 {nullptr, nullptr}}; 164 static PyModuleDef def = {PyModuleDef_HEAD_INIT, "test_module", nullptr, 0, 165 methods}; 166 PyObjectPtr module(PyModule_Create(&def)); 167 moduleSet("__main__", "test_module", module); 168 PyCompilerFlags flags = _PyCompilerFlags_INIT; 169 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 170 ASSERT_EQ(PyRun_SimpleStringFlags( 171 "result = test_module.test_merge_compiler_flags()", &flags), 172 0); 173 PyObjectPtr result(mainModuleGet("result")); 174 ASSERT_FALSE(0xfba0000 & CO_FUTURE_BARRY_AS_BDFL); 175 EXPECT_TRUE(isLongEqualsLong(result, 0xfba0000 | CO_FUTURE_BARRY_AS_BDFL)); 176} 177 178TEST_F(CevalExtensionApiTest, CallObjectWithNonTupleArgsRaisesTypeError) { 179 PyRun_SimpleString(R"( 180def fn(): 181 pass 182)"); 183 PyObjectPtr fn(mainModuleGet("fn")); 184 PyObjectPtr args(PyList_New(0)); 185 PyEval_CallObject(fn, args); 186 ASSERT_NE(PyErr_Occurred(), nullptr); 187 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 188} 189 190TEST_F(CevalExtensionApiTest, CallObjectWithNullArgsReturnsResult) { 191 PyRun_SimpleString(R"( 192def fn(): 193 return 19 194)"); 195 PyObjectPtr fn(mainModuleGet("fn")); 196 PyObjectPtr result(PyEval_CallObject(fn, nullptr)); 197 ASSERT_EQ(PyErr_Occurred(), nullptr); 198 EXPECT_TRUE(isLongEqualsLong(result, 19)); 199} 200 201TEST_F(CevalExtensionApiTest, CallObjectWithTupleArgsReturnsResult) { 202 PyRun_SimpleString(R"( 203def fn(*args): 204 return args[0] 205)"); 206 PyObjectPtr fn(mainModuleGet("fn")); 207 PyObjectPtr args(PyTuple_New(1)); 208 PyTuple_SetItem(args, 0, PyLong_FromLong(3)); 209 PyObjectPtr result(PyEval_CallObject(fn, args)); 210 ASSERT_EQ(PyErr_Occurred(), nullptr); 211 EXPECT_TRUE(isLongEqualsLong(result, 3)); 212} 213 214TEST_F(CevalExtensionApiTest, 215 CallObjectWithKeywordsWithNonTupleArgsRaisesTypeError) { 216 PyRun_SimpleString(R"( 217def fn(): 218 pass 219)"); 220 PyObjectPtr fn(mainModuleGet("fn")); 221 PyObjectPtr args(PyList_New(0)); 222 PyEval_CallObjectWithKeywords(fn, args, nullptr); 223 ASSERT_NE(PyErr_Occurred(), nullptr); 224 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 225} 226 227TEST_F(CevalExtensionApiTest, 228 CallObjectWithKeywordsWithNonDictKwargsRaisesTypeError) { 229 PyRun_SimpleString(R"( 230def fn(): 231 pass 232)"); 233 PyObjectPtr fn(mainModuleGet("fn")); 234 PyObjectPtr kwargs(PyList_New(0)); 235 PyEval_CallObjectWithKeywords(fn, nullptr, kwargs); 236 ASSERT_NE(PyErr_Occurred(), nullptr); 237 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 238} 239 240TEST_F(CevalExtensionApiTest, CallObjectWithKeywordsWithNullArgsReturnsResult) { 241 PyRun_SimpleString(R"( 242def fn(*args, **kwargs): 243 return kwargs["kwarg"] 244)"); 245 PyObjectPtr fn(mainModuleGet("fn")); 246 PyObjectPtr kwargs(PyDict_New()); 247 PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg")); 248 PyObjectPtr kwarg_value(PyLong_FromLong(2)); 249 PyDict_SetItem(kwargs, kwarg_name, kwarg_value); 250 PyObjectPtr result(PyEval_CallObjectWithKeywords(fn, nullptr, kwargs)); 251 ASSERT_EQ(PyErr_Occurred(), nullptr); 252 EXPECT_TRUE(isLongEqualsLong(result, 2)); 253} 254 255TEST_F(CevalExtensionApiTest, 256 CallObjectWithKeywordsWithArgsAndKeywordsReturnsResult) { 257 PyRun_SimpleString(R"( 258def fn(*args, **kwargs): 259 return kwargs["kwarg"] + args[0] 260)"); 261 PyObjectPtr fn(mainModuleGet("fn")); 262 PyObjectPtr args(PyTuple_New(1)); 263 PyTuple_SetItem(args, 0, PyLong_FromLong(2)); 264 PyObjectPtr kwargs(PyDict_New()); 265 PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg")); 266 PyObjectPtr kwarg_value(PyLong_FromLong(2)); 267 PyDict_SetItem(kwargs, kwarg_name, kwarg_value); 268 PyObjectPtr result(PyEval_CallObjectWithKeywords(fn, args, kwargs)); 269 ASSERT_EQ(PyErr_Occurred(), nullptr); 270 EXPECT_TRUE(isLongEqualsLong(result, 4)); 271} 272 273} // namespace testing 274} // namespace py