this repo has no description
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