this repo has no description
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
8extern "C" int _PyThreadState_GetRecursionDepth(PyThreadState*);
9
10namespace py {
11namespace testing {
12
13using PystateExtensionApiTest = ExtensionApi;
14using PystateExtensionApiTestDeathTest = ExtensionApi;
15
16TEST_F(PystateExtensionApiTestDeathTest, AddModuleWithNullDefDeathTest) {
17 EXPECT_DEATH(PyState_AddModule(Py_None, nullptr),
18 "Module Definition is NULL");
19}
20
21TEST_F(PystateExtensionApiTestDeathTest, AddExistingModuleDoesNotOverride) {
22 static struct PyModuleDef def = {
23 PyModuleDef_HEAD_INIT,
24 "foo",
25 "docs",
26 0,
27 nullptr,
28 nullptr,
29 nullptr,
30 nullptr,
31 };
32 PyModuleDef_Init(&def);
33 PyObjectPtr module(PyModule_New("foo"));
34 ASSERT_NE(module, nullptr);
35 ASSERT_EQ(PyState_AddModule(module, &def), 0);
36 EXPECT_DEATH(PyState_AddModule(module, &def), "Module already added!");
37}
38
39TEST_F(PystateExtensionApiTest, AddModuleWithSlotsRaisesSystemError) {
40 struct PyModuleDef_Slot slots[] = {
41 {0, nullptr},
42 };
43 struct PyModuleDef def = {
44 PyModuleDef_HEAD_INIT,
45 "rutabaga",
46 "I'm sure this module will turnip somewhere.",
47 0,
48 nullptr,
49 slots,
50 nullptr,
51 nullptr,
52 };
53 PyModuleDef_Init(&def);
54 EXPECT_EQ(PyState_AddModule(Py_None, &def), -1);
55 ASSERT_NE(PyErr_Occurred(), nullptr);
56 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
57}
58
59TEST_F(PystateExtensionApiTest, AddModuleAddsModule) {
60 static struct PyModuleDef def = {
61 PyModuleDef_HEAD_INIT,
62 "rutabaga",
63 "I'm sure this module will turnip somewhere.",
64 0,
65 nullptr,
66 nullptr,
67 nullptr,
68 nullptr,
69 };
70 PyObject* module = PyModule_Create(&def);
71 ASSERT_NE(module, nullptr);
72 ASSERT_EQ(PyState_AddModule(module, &def), 0);
73 ASSERT_EQ(PyErr_Occurred(), nullptr);
74 PyObject* found_module = PyState_FindModule(&def);
75 ASSERT_NE(found_module, nullptr);
76 ASSERT_EQ(PyErr_Occurred(), nullptr);
77 ASSERT_TRUE(PyModule_CheckExact(found_module));
78 PyObjectPtr found_name(PyModule_GetNameObject(found_module));
79 PyObjectPtr module_name(PyModule_GetNameObject(module));
80 EXPECT_EQ(PyUnicode_Compare(found_name, module_name), 0);
81 Py_DECREF(module);
82}
83
84TEST_F(PystateExtensionApiTest, _PyState_AddModuleWithSlotsRaisesSystemError) {
85 struct PyModuleDef_Slot slots[] = {
86 {0, nullptr},
87 };
88 struct PyModuleDef def = {
89 PyModuleDef_HEAD_INIT, "foo", "bar", 0, nullptr, slots, nullptr, nullptr,
90 };
91 PyModuleDef_Init(&def);
92 EXPECT_EQ(PyState_AddModule(Py_None, &def), -1);
93 ASSERT_NE(PyErr_Occurred(), nullptr);
94 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
95}
96
97TEST_F(PystateExtensionApiTest, _PyState_AddModuleTwiceAddsModule) {
98 static struct PyModuleDef def = {
99 PyModuleDef_HEAD_INIT,
100 "foo",
101 "bar",
102 0,
103 nullptr,
104 nullptr,
105 nullptr,
106 nullptr,
107 };
108 PyObject* module = PyModule_Create(&def);
109 ASSERT_NE(module, nullptr);
110 ASSERT_EQ(_PyState_AddModule(module, &def), 0);
111 ASSERT_EQ(PyErr_Occurred(), nullptr);
112 ASSERT_EQ(_PyState_AddModule(module, &def), 0);
113 ASSERT_EQ(PyErr_Occurred(), nullptr);
114 PyObject* found_module = PyState_FindModule(&def);
115 ASSERT_NE(found_module, nullptr);
116 ASSERT_EQ(PyErr_Occurred(), nullptr);
117 ASSERT_TRUE(PyModule_CheckExact(found_module));
118 PyObjectPtr found_name(PyModule_GetNameObject(found_module));
119 PyObjectPtr module_name(PyModule_GetNameObject(module));
120 EXPECT_EQ(PyUnicode_Compare(found_name, module_name), 0);
121 Py_DECREF(module);
122}
123
124TEST_F(PystateExtensionApiTest, FindModuleWithSlotsReturnsNull) {
125 struct PyModuleDef def = {
126 PyModuleDef_HEAD_INIT,
127 "builtins",
128 "Uh, the builtins module, I guess",
129 0,
130 nullptr,
131 reinterpret_cast<PyModuleDef_Slot*>(5),
132 nullptr,
133 nullptr,
134 };
135 PyModuleDef_Init(&def);
136 EXPECT_EQ(PyState_FindModule(&def), nullptr);
137 ASSERT_EQ(PyErr_Occurred(), nullptr);
138}
139
140TEST_F(PystateExtensionApiTest, FindModuleWithNonExistentModuleReturnsNull) {
141 struct PyModuleDef def = {
142 PyModuleDef_HEAD_INIT,
143 "rutabaga",
144 "I'm sure this module will turnip somewhere.",
145 0,
146 nullptr,
147 nullptr,
148 nullptr,
149 nullptr,
150 };
151 PyModuleDef_Init(&def);
152 EXPECT_EQ(PyState_FindModule(&def), nullptr);
153 ASSERT_EQ(PyErr_Occurred(), nullptr);
154}
155
156static int recurseUntilLimit(PyThreadState* tstate, int limit) {
157 if (Py_EnterRecursiveCall("") != 0) {
158 return -1;
159 }
160
161 int result = 0;
162 if (_PyThreadState_GetRecursionDepth(tstate) != limit) {
163 result = recurseUntilLimit(tstate, limit);
164 }
165 Py_LeaveRecursiveCall();
166 return result;
167}
168
169TEST_F(PystateExtensionApiTest, RecursionDepthStopsInfiniteRecursion) {
170 PyThreadState* tstate = PyThreadState_Get();
171 Py_SetRecursionLimit(50);
172 int limit = Py_GetRecursionLimit() - 1;
173 EXPECT_EQ(recurseUntilLimit(tstate, limit), 0);
174 EXPECT_EQ(PyErr_Occurred(), nullptr);
175}
176
177TEST_F(PystateExtensionApiTest,
178 RecursionDepthExceedingLimitRaisesRecursionError) {
179 PyThreadState* tstate = PyThreadState_Get();
180 Py_SetRecursionLimit(50);
181 int limit = Py_GetRecursionLimit() + 1;
182 EXPECT_EQ(recurseUntilLimit(tstate, limit), -1);
183 EXPECT_NE(PyErr_Occurred(), nullptr);
184 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_RecursionError));
185}
186
187} // namespace testing
188} // namespace py