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 TupleExtensionApiTest = ExtensionApi;
12
13TEST_F(TupleExtensionApiTest, CheckWithTupleSubclassReturnsTrue) {
14 PyRun_SimpleString(R"(
15class Foo(tuple): pass
16obj = Foo((1, 2));
17)");
18 PyObjectPtr obj(mainModuleGet("obj"));
19 EXPECT_TRUE(PyTuple_Check(obj));
20}
21
22TEST_F(TupleExtensionApiTest, CheckExactWithTupleSubclassReturnsFalse) {
23 PyRun_SimpleString(R"(
24class Foo(tuple): pass
25obj = Foo((1, 2));
26)");
27 PyObjectPtr obj(mainModuleGet("obj"));
28 EXPECT_FALSE(PyTuple_CheckExact(obj));
29}
30
31TEST_F(TupleExtensionApiTest, NewAndSize) {
32 Py_ssize_t length = 5;
33 PyObjectPtr pytuple(PyTuple_New(length));
34 Py_ssize_t result = PyTuple_Size(pytuple);
35 EXPECT_EQ(result, length);
36}
37
38TEST_F(TupleExtensionApiTest, SetItemWithNonTupleReturnsNegative) {
39 Py_INCREF(Py_None);
40 int result = PyTuple_SetItem(Py_True, 0, Py_None);
41 EXPECT_EQ(result, -1);
42
43 ASSERT_NE(PyErr_Occurred(), nullptr);
44 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
45}
46
47TEST_F(TupleExtensionApiTest, SetItemWithInvalidIndexReturnsNegative) {
48 PyObjectPtr pytuple(PyTuple_New(1));
49 Py_INCREF(Py_None);
50 int result = PyTuple_SetItem(pytuple, 2, Py_None);
51 EXPECT_EQ(result, -1);
52
53 ASSERT_NE(PyErr_Occurred(), nullptr);
54 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
55}
56
57TEST_F(TupleExtensionApiTest, SetItemReturnsZero) {
58 PyObjectPtr pytuple(PyTuple_New(1));
59 Py_INCREF(Py_None);
60 int result = PyTuple_SetItem(pytuple, 0, Py_None);
61 EXPECT_EQ(result, 0);
62}
63
64TEST_F(TupleExtensionApiTest, SetItemWithTupleSubclassReturnsZero) {
65 PyRun_SimpleString(R"(
66class Foo(tuple): pass
67obj = Foo((1, 2));
68)");
69 PyObjectPtr pytuple(mainModuleGet("obj"));
70 // PyTuple_SetItem() wants the tuple's reference count to be 1, so remove the
71 // reference from __main__.
72 moduleSet("__main__", "obj", Py_None);
73 Py_INCREF(Py_None);
74 int result = PyTuple_SetItem(pytuple, 0, Py_None);
75 ASSERT_EQ(PyErr_Occurred(), nullptr);
76 EXPECT_EQ(result, 0);
77 EXPECT_EQ(PyTuple_GetItem(pytuple, 0), Py_None);
78}
79
80TEST_F(TupleExtensionApiTest, GetItemFromNonTupleReturnsNull) {
81 PyObject* pytuple = PyTuple_GetItem(Py_None, 0);
82 EXPECT_EQ(nullptr, pytuple);
83}
84
85TEST_F(TupleExtensionApiTest, GetItemOutOfBoundsRaisesIndexError) {
86 Py_ssize_t length = 5;
87 PyObjectPtr pytuple(PyTuple_New(length));
88
89 // Get item out of bounds
90 PyObject* pyresult = PyTuple_GetItem(pytuple, -1);
91 EXPECT_EQ(nullptr, pyresult);
92 ASSERT_NE(PyErr_Occurred(), nullptr);
93 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
94
95 PyErr_Clear();
96 pyresult = PyTuple_GetItem(pytuple, length);
97 EXPECT_EQ(nullptr, pyresult);
98 ASSERT_NE(PyErr_Occurred(), nullptr);
99 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
100}
101
102TEST_F(TupleExtensionApiTest, GetItemReturnsSameItem) {
103 Py_ssize_t length = 5;
104 Py_ssize_t pos = 3;
105 Py_ssize_t int_value = 10;
106 PyObjectPtr pytuple(PyTuple_New(length));
107 PyObject* pyitem = PyLong_FromLong(int_value);
108 ASSERT_EQ(PyTuple_SetItem(pytuple, pos, pyitem), 0);
109
110 // Get item
111 PyObject* pyresult = PyTuple_GetItem(pytuple, pos);
112 EXPECT_NE(nullptr, pyresult);
113 EXPECT_EQ(PyLong_AsLong(pyresult), int_value);
114}
115
116TEST_F(TupleExtensionApiTest, GetItemReturnsBorrowedReference) {
117 Py_ssize_t length = 5;
118 Py_ssize_t pos = 3;
119 PyObjectPtr pytuple(PyTuple_New(length));
120 PyObjectPtr pyitem(PyLong_FromLong(0));
121 Py_INCREF(pyitem); // keep an extra reference for checking below SetItem
122 ASSERT_EQ(PyTuple_SetItem(pytuple, pos, pyitem), 0);
123
124 long refcnt = Py_REFCNT(pyitem);
125 PyObject* pyresult = PyTuple_GetItem(pytuple, pos);
126 // PyTuple_GetItem "borrows" a reference for the return value. Verify the
127 // reference count did not change.
128 EXPECT_EQ(Py_REFCNT(pyresult), refcnt);
129}
130
131TEST_F(TupleExtensionApiTest, GetItemWithTupleSubclassReturnsValue) {
132 PyRun_SimpleString(R"(
133class Foo(tuple): pass
134obj = Foo((1, 2));
135)");
136 PyObjectPtr obj(mainModuleGet("obj"));
137 PyObject* first = PyTuple_GetItem(obj, 0);
138 PyObject* second = PyTuple_GetItem(obj, 1);
139 EXPECT_EQ(PyLong_AsLong(first), 1);
140 EXPECT_EQ(PyLong_AsLong(second), 2);
141}
142
143TEST_F(TupleExtensionApiTest, PackZeroReturnsEmptyTuple) {
144 PyObjectPtr pytuple(PyTuple_Pack(0));
145 Py_ssize_t result = PyTuple_Size(pytuple);
146 EXPECT_EQ(result, 0);
147}
148
149TEST_F(TupleExtensionApiTest, PackOneValue) {
150 Py_ssize_t length = 1;
151 const int int_value = 5;
152 PyObjectPtr pylong(PyLong_FromLong(int_value));
153 PyObjectPtr pytuple(PyTuple_Pack(length, pylong.get()));
154
155 PyObject* pyresult = PyTuple_GetItem(pytuple, 0);
156 EXPECT_EQ(PyLong_AsLong(pyresult), int_value);
157}
158
159TEST_F(TupleExtensionApiTest, PackTwoValues) {
160 Py_ssize_t length = 2;
161 const int int_value1 = 5;
162 const int int_value2 = 12;
163 PyObjectPtr pylong1(PyLong_FromLong(int_value1));
164 PyObjectPtr pylong2(PyLong_FromLong(int_value2));
165 PyObjectPtr pytuple(PyTuple_Pack(length, pylong1.get(), pylong2.get()));
166
167 PyObject* pyresult1 = PyTuple_GetItem(pytuple, 0);
168 PyObject* pyresult2 = PyTuple_GetItem(pytuple, 1);
169 EXPECT_EQ(PyLong_AsLong(pyresult1), int_value1);
170 EXPECT_EQ(PyLong_AsLong(pyresult2), int_value2);
171}
172
173TEST_F(TupleExtensionApiTest, GetSliceWithNullRaisesSystemError) {
174 ASSERT_EQ(PyTuple_GetSlice(nullptr, 0, 0), nullptr);
175 ASSERT_NE(PyErr_Occurred(), nullptr);
176 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
177}
178
179TEST_F(TupleExtensionApiTest, GetSliceWithNonTupleRaisesSystemError) {
180 ASSERT_EQ(PyTuple_GetSlice(Py_None, 0, 0), nullptr);
181 ASSERT_NE(PyErr_Occurred(), nullptr);
182 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
183}
184
185TEST_F(TupleExtensionApiTest, GetSliceWithLowSmallerThanZeroStartsAtZero) {
186 PyObjectPtr tuple(PyTuple_New(3));
187 PyObjectPtr zero(PyLong_FromLong(0));
188 // The calls to Py_INCREF in this function exist because SetItem steals
189 // references and these items need to be kept alive for later checking.
190 Py_INCREF(zero);
191 PyTuple_SetItem(tuple, 0, zero);
192 PyObjectPtr one(PyLong_FromLong(1));
193 Py_INCREF(one);
194 PyTuple_SetItem(tuple, 1, one);
195 PyObjectPtr two(PyLong_FromLong(2));
196 Py_INCREF(two);
197 PyTuple_SetItem(tuple, 2, two);
198
199 PyObjectPtr result(PyTuple_GetSlice(tuple, -5, 3));
200 ASSERT_NE(result, nullptr);
201 ASSERT_EQ(PyErr_Occurred(), nullptr);
202 ASSERT_TRUE(PyTuple_CheckExact(result));
203 EXPECT_EQ(tuple, result);
204 EXPECT_EQ(PyTuple_Size(result), 3);
205 EXPECT_EQ(PyTuple_GetItem(result, 0), zero);
206 EXPECT_EQ(PyTuple_GetItem(result, 1), one);
207 EXPECT_EQ(PyTuple_GetItem(result, 2), two);
208}
209
210TEST_F(TupleExtensionApiTest,
211 GetSliceWithLowLargerThanLengthReturnsEmptyTuple) {
212 PyObjectPtr tuple(PyTuple_New(3));
213 PyTuple_SetItem(tuple, 0, PyLong_FromLong(0));
214 PyTuple_SetItem(tuple, 1, PyLong_FromLong(1));
215 PyTuple_SetItem(tuple, 2, PyLong_FromLong(2));
216
217 PyObjectPtr result(PyTuple_GetSlice(tuple, 15, 3));
218 ASSERT_NE(result, nullptr);
219 ASSERT_EQ(PyErr_Occurred(), nullptr);
220 ASSERT_TRUE(PyTuple_CheckExact(result));
221 EXPECT_NE(tuple, result);
222 EXPECT_EQ(PyTuple_Size(result), 0);
223}
224
225TEST_F(TupleExtensionApiTest,
226 GetSliceWithOutOfBoundsHighStartsAtLowAndReturnsEmptyTuple) {
227 PyObjectPtr tuple(PyTuple_New(3));
228 PyTuple_SetItem(tuple, 0, PyLong_FromLong(0));
229 PyTuple_SetItem(tuple, 1, PyLong_FromLong(1));
230 PyTuple_SetItem(tuple, 2, PyLong_FromLong(2));
231
232 PyObjectPtr result(PyTuple_GetSlice(tuple, 1, 0));
233 ASSERT_NE(result, nullptr);
234 ASSERT_EQ(PyErr_Occurred(), nullptr);
235 ASSERT_TRUE(PyTuple_CheckExact(result));
236 EXPECT_NE(tuple, result);
237 EXPECT_EQ(PyTuple_Size(result), 0);
238}
239
240TEST_F(TupleExtensionApiTest, GetSliceWithHighLargerThanLengthEndsAtLength) {
241 PyObjectPtr tuple(PyTuple_New(3));
242 PyObjectPtr zero(PyLong_FromLong(0));
243 Py_INCREF(zero);
244 PyTuple_SetItem(tuple, 0, zero);
245 PyObjectPtr one(PyLong_FromLong(1));
246 Py_INCREF(one);
247 PyTuple_SetItem(tuple, 1, one);
248 PyObjectPtr two(PyLong_FromLong(2));
249 Py_INCREF(two);
250 PyTuple_SetItem(tuple, 2, two);
251
252 PyObjectPtr result(PyTuple_GetSlice(tuple, 0, 20));
253 ASSERT_NE(result, nullptr);
254 ASSERT_EQ(PyErr_Occurred(), nullptr);
255 ASSERT_TRUE(PyTuple_CheckExact(result));
256 EXPECT_EQ(tuple, result);
257 EXPECT_EQ(PyTuple_Size(result), 3);
258 EXPECT_EQ(PyTuple_GetItem(result, 0), zero);
259 EXPECT_EQ(PyTuple_GetItem(result, 1), one);
260 EXPECT_EQ(PyTuple_GetItem(result, 2), two);
261}
262
263TEST_F(TupleExtensionApiTest,
264 GetSliceWithZeroLowAndLengthHighReturnsOriginalTuple) {
265 PyObjectPtr tuple(PyTuple_New(3));
266 PyObjectPtr zero(PyLong_FromLong(0));
267 Py_INCREF(zero);
268 PyTuple_SetItem(tuple, 0, zero);
269 PyObjectPtr one(PyLong_FromLong(1));
270 Py_INCREF(one);
271 PyTuple_SetItem(tuple, 1, one);
272 PyObjectPtr two(PyLong_FromLong(2));
273 Py_INCREF(two);
274 PyTuple_SetItem(tuple, 2, two);
275
276 PyObjectPtr result(PyTuple_GetSlice(tuple, 0, 3));
277 ASSERT_NE(result, nullptr);
278 ASSERT_EQ(PyErr_Occurred(), nullptr);
279 ASSERT_TRUE(PyTuple_CheckExact(result));
280 EXPECT_EQ(tuple, result);
281 EXPECT_EQ(PyTuple_Size(result), 3);
282 EXPECT_EQ(PyTuple_GetItem(result, 0), zero);
283 EXPECT_EQ(PyTuple_GetItem(result, 1), one);
284 EXPECT_EQ(PyTuple_GetItem(result, 2), two);
285}
286
287TEST_F(TupleExtensionApiTest, GetSliceReturnsSmallerTuple) {
288 PyObjectPtr tuple(PyTuple_New(4));
289 PyTuple_SetItem(tuple, 0, PyLong_FromLong(0));
290 PyObjectPtr one(PyLong_FromLong(1));
291 Py_INCREF(one);
292 PyTuple_SetItem(tuple, 1, one);
293 PyObjectPtr two(PyLong_FromLong(2));
294 Py_INCREF(two);
295 PyTuple_SetItem(tuple, 2, two);
296 PyTuple_SetItem(tuple, 3, PyLong_FromLong(3));
297
298 PyObjectPtr result(PyTuple_GetSlice(tuple, 1, 3));
299 ASSERT_NE(result, nullptr);
300 ASSERT_EQ(PyErr_Occurred(), nullptr);
301 ASSERT_TRUE(PyTuple_CheckExact(result));
302 EXPECT_EQ(PyTuple_Size(result), 2);
303 EXPECT_EQ(PyTuple_GetItem(result, 0), one);
304 EXPECT_EQ(PyTuple_GetItem(result, 1), two);
305}
306
307} // namespace testing
308} // namespace py