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
8namespace py {
9namespace testing {
10
11using ClassExtensionApiTest = ExtensionApi;
12
13TEST_F(ClassExtensionApiTest, InstanceMethodNewReturnsInstanceMethod) {
14 PyRun_SimpleString(R"(
15def foo():
16 pass
17)");
18 PyObjectPtr foo(mainModuleGet("foo"));
19 PyObjectPtr method(PyInstanceMethod_New(foo));
20 EXPECT_NE(method, nullptr);
21 EXPECT_TRUE(PyInstanceMethod_Check(method.get()));
22 EXPECT_NE(method, foo);
23}
24
25TEST_F(ClassExtensionApiTest, InstanceMethodGETFUNCTIONReturnsFunction) {
26 PyRun_SimpleString(R"(
27def foo():
28 pass
29)");
30 PyObjectPtr foo(mainModuleGet("foo"));
31 PyObjectPtr method(PyInstanceMethod_New(foo));
32 EXPECT_NE(method, nullptr);
33 EXPECT_EQ(PyInstanceMethod_GET_FUNCTION(method.get()), foo);
34}
35
36TEST_F(ClassExtensionApiTest, CallWithInstanceMethodCallsFunction) {
37 PyRun_SimpleString(R"(
38def foo():
39 return 123
40)");
41 PyObjectPtr foo(mainModuleGet("foo"));
42 PyObjectPtr method(PyInstanceMethod_New(foo));
43 EXPECT_NE(method, nullptr);
44 PyObjectPtr result(PyObject_CallFunctionObjArgs(method, nullptr));
45 EXPECT_EQ(PyErr_Occurred(), nullptr);
46 EXPECT_TRUE(isLongEqualsLong(result, 123));
47}
48
49TEST_F(ClassExtensionApiTest,
50 InstanceMethodDunderGetWithNoneObjectReturnsFunction) {
51 PyRun_SimpleString(R"(
52def foo():
53 return 123
54)");
55 PyObjectPtr foo(mainModuleGet("foo"));
56 PyObjectPtr method(PyInstanceMethod_New(foo));
57 EXPECT_NE(method, nullptr);
58 PyObjectPtr none((Borrowed(Py_None)));
59 PyObjectPtr non_none(PyLong_FromLong(123));
60 PyObjectPtr result(
61 PyObject_CallMethod(method, "__get__", "OO", none.get(), non_none.get()));
62 ASSERT_EQ(PyErr_Occurred(), nullptr);
63 EXPECT_NE(result, nullptr);
64 EXPECT_EQ(result, foo);
65}
66
67TEST_F(ClassExtensionApiTest,
68 InstanceMethodDunderGetAttrWithNonExistentAttrRaisesAttributeError) {
69 PyRun_SimpleString(R"(
70def foo():
71 pass
72)");
73 PyObjectPtr foo(mainModuleGet("foo"));
74 PyObjectPtr method(PyInstanceMethod_New(foo));
75 ASSERT_NE(method, nullptr);
76 // Call the "__getattr__" method of the instancemethod, check
77 // behavior for requesting a non-existent attribute.
78 PyObjectPtr result(PyObject_GetAttrString(method, "bar"));
79 EXPECT_EQ(result, nullptr);
80 ASSERT_NE(PyErr_Occurred(), nullptr);
81 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
82}
83
84TEST_F(ClassExtensionApiTest,
85 InstanceMethodDunderGetAttrReturnsAttributeOfUnderlyingFunction) {
86 PyRun_SimpleString(R"(
87def foo():
88 pass
89foo.bar = 123
90)");
91 PyObjectPtr foo(mainModuleGet("foo"));
92 PyObjectPtr method(PyInstanceMethod_New(foo));
93 ASSERT_NE(method, nullptr);
94 // Call the "__getattr__" method of the instancemethod, check
95 // behavior for requesting an attribute on the underlying function.
96 PyObjectPtr result(PyObject_GetAttrString(method, "bar"));
97 EXPECT_TRUE(isLongEqualsLong(result, 123));
98 EXPECT_EQ(PyErr_Occurred(), nullptr);
99}
100
101TEST_F(ClassExtensionApiTest,
102 InstanceMethodDunderGetAttrReturnsAttributeOfInstanceMethod) {
103 PyRun_SimpleString(R"(
104def foo():
105 pass
106)");
107 PyObjectPtr foo(mainModuleGet("foo"));
108 PyObjectPtr method(PyInstanceMethod_New(foo));
109 ASSERT_NE(method, nullptr);
110 // Call the "__getattr__" method of the instancemethod, check
111 // behavior for requesting an attribute on the instancemethod (and
112 // *not* the underlying function).
113 PyObjectPtr result(PyObject_GetAttrString(method, "__func__"));
114 EXPECT_EQ(result, foo);
115 EXPECT_EQ(PyErr_Occurred(), nullptr);
116}
117
118TEST_F(ClassExtensionApiTest,
119 InstanceMethodDunderGetWithNonNoneObjectReturnsMethod) {
120 PyRun_SimpleString(R"(
121def foo():
122 return 123
123)");
124 PyObjectPtr foo(mainModuleGet("foo"));
125 PyObjectPtr method(PyInstanceMethod_New(foo));
126 EXPECT_NE(method, nullptr);
127 PyObjectPtr instance(PyLong_FromLong(456));
128 PyObjectPtr none((Borrowed(Py_None)));
129 PyObjectPtr result(
130 PyObject_CallMethod(method, "__get__", "OO", instance.get(), none.get()));
131 EXPECT_NE(result, nullptr);
132 EXPECT_TRUE(PyMethod_Check(result.get()));
133}
134
135TEST_F(ClassExtensionApiTest, InstanceMethodLessThanRaisesTypeError) {
136 PyRun_SimpleString(R"(
137def foo():
138 return 123
139)");
140 PyObjectPtr foo(mainModuleGet("foo"));
141 PyObjectPtr method(PyInstanceMethod_New(foo));
142 EXPECT_NE(method, nullptr);
143 ASSERT_EQ(PyObject_RichCompare(method, method, Py_LT), nullptr);
144 ASSERT_NE(PyErr_Occurred(), nullptr);
145 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
146}
147
148TEST_F(ClassExtensionApiTest, InstanceMethodLessEqualRaisesTypeError) {
149 PyRun_SimpleString(R"(
150def foo():
151 return 123
152)");
153 PyObjectPtr foo(mainModuleGet("foo"));
154 PyObjectPtr method(PyInstanceMethod_New(foo));
155 EXPECT_NE(method, nullptr);
156 ASSERT_EQ(PyObject_RichCompare(method, method, Py_LE), nullptr);
157 ASSERT_NE(PyErr_Occurred(), nullptr);
158 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
159}
160
161TEST_F(ClassExtensionApiTest, InstanceMethodGreaterThanRaisesTypeError) {
162 PyRun_SimpleString(R"(
163def foo():
164 return 123
165)");
166 PyObjectPtr foo(mainModuleGet("foo"));
167 PyObjectPtr method(PyInstanceMethod_New(foo));
168 EXPECT_NE(method, nullptr);
169 ASSERT_EQ(PyObject_RichCompare(method, method, Py_GT), nullptr);
170 ASSERT_NE(PyErr_Occurred(), nullptr);
171 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
172}
173
174TEST_F(ClassExtensionApiTest, InstanceMethodGreaterEqualRaisesTypeError) {
175 PyRun_SimpleString(R"(
176def foo():
177 return 123
178)");
179 PyObjectPtr foo(mainModuleGet("foo"));
180 PyObjectPtr method(PyInstanceMethod_New(foo));
181 EXPECT_NE(method, nullptr);
182 ASSERT_EQ(PyObject_RichCompare(method, method, Py_GE), nullptr);
183 ASSERT_NE(PyErr_Occurred(), nullptr);
184 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
185}
186
187TEST_F(ClassExtensionApiTest, FunctionReturnsFunction) {
188 PyRun_SimpleString(R"(
189def foo():
190 pass
191)");
192 PyObjectPtr foo(mainModuleGet("foo"));
193 PyObjectPtr bar(PyLong_FromLong(42));
194 PyObjectPtr method(PyMethod_New(foo, bar));
195 EXPECT_EQ(PyMethod_Function(method), foo);
196}
197
198TEST_F(ClassExtensionApiTest, GetFunctionReturnsFunction) {
199 PyRun_SimpleString(R"(
200def foo():
201 pass
202)");
203 PyObjectPtr foo(mainModuleGet("foo"));
204 PyObjectPtr bar(PyLong_FromLong(42));
205 PyObjectPtr method(PyMethod_New(foo, bar));
206 EXPECT_EQ(PyMethod_GET_FUNCTION(method.get()), foo);
207}
208
209TEST_F(ClassExtensionApiTest, NewWithNullSelfRaisesRuntimeError) {
210 PyRun_SimpleString(R"(
211def foo(x):
212 return x
213)");
214 PyObjectPtr foo(mainModuleGet("foo"));
215 PyObject* method = PyMethod_New(foo, nullptr);
216 ASSERT_NE(PyErr_Occurred(), nullptr);
217 EXPECT_EQ(method, nullptr);
218 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
219}
220
221TEST_F(ClassExtensionApiTest, NewWithNoArgsReturnsBoundObject) {
222 PyRun_SimpleString(R"(
223def foo(x):
224 return x
225)");
226 PyObjectPtr foo(mainModuleGet("foo"));
227 PyObjectPtr integer(PyLong_FromLong(123));
228 PyObjectPtr method(PyMethod_New(foo, integer));
229 PyObjectPtr args(PyTuple_New(0));
230 PyObjectPtr result(PyObject_CallObject(method, args));
231 ASSERT_NE(result, nullptr);
232 EXPECT_EQ(result, integer);
233}
234
235TEST_F(ClassExtensionApiTest, CheckWithNonMethodReturnsFalse) {
236 PyObjectPtr pylong(PyLong_FromLong(10));
237 EXPECT_EQ(PyMethod_Check(pylong.get()), 0);
238}
239
240TEST_F(ClassExtensionApiTest, CheckWithMethodReturnsTrue) {
241 PyRun_SimpleString(R"(
242def foo(x):
243 return x
244)");
245 PyObjectPtr foo(mainModuleGet("foo"));
246 PyObjectPtr integer(PyLong_FromLong(123));
247 PyObjectPtr method(PyMethod_New(foo, integer));
248 EXPECT_EQ(PyMethod_Check(method.get()), 1);
249}
250
251TEST_F(ClassExtensionApiTest, SelfReturnsSelf) {
252 PyRun_SimpleString(R"(
253def foo():
254 pass
255)");
256 PyObjectPtr foo(mainModuleGet("foo"));
257 PyObjectPtr bar(PyLong_FromLong(42));
258 PyObjectPtr method(PyMethod_New(foo, bar));
259 EXPECT_EQ(PyMethod_Self(method), bar);
260}
261
262TEST_F(ClassExtensionApiTest, GetSelfReturnsSelf) {
263 PyRun_SimpleString(R"(
264def foo():
265 pass
266)");
267 PyObjectPtr foo(mainModuleGet("foo"));
268 PyObjectPtr bar(PyLong_FromLong(42));
269 PyObjectPtr method(PyMethod_New(foo, bar));
270 EXPECT_EQ(PyMethod_GET_SELF(method.get()), bar);
271}
272
273} // namespace testing
274} // namespace py