this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "Python.h"
3
4#include "capi-fixture.h"
5#include "capi-testing.h"
6
7namespace py {
8namespace testing {
9
10using GetArgsExtensionApiTest = ExtensionApi;
11
12TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromDict) {
13 PyObjectPtr args(PyTuple_New(0));
14 PyObjectPtr kwargs(PyDict_New());
15 PyObjectPtr key(PyUnicode_FromString("first"));
16 PyObjectPtr value(PyLong_FromLong(42));
17 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
18
19 const char* const keywords[] = {"first", nullptr};
20 static _PyArg_Parser parser = {"O:ParseTupleAndKeywordsFastFromDict",
21 keywords};
22 PyObject* out = Py_None;
23
24 EXPECT_EQ(_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out), 1);
25 EXPECT_EQ(PyLong_AsLong(out), 42);
26}
27
28TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromTuple) {
29 PyObjectPtr args(PyTuple_New(1));
30 ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(43)));
31 PyObjectPtr kwargs(PyDict_New());
32
33 const char* const keywords[] = {"first", nullptr};
34 static _PyArg_Parser parser = {"O:ParseTupleAndKeywordsFastFromTuple",
35 keywords};
36 PyObject* out = Py_None;
37
38 EXPECT_EQ(_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out), 1);
39 EXPECT_EQ(PyLong_AsLong(out), 43);
40}
41
42TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromTupleAndDict) {
43 PyObjectPtr args(PyTuple_New(1));
44 ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(44)));
45 PyObjectPtr kwargs(PyDict_New());
46 PyObjectPtr key(PyUnicode_FromString("second"));
47 PyObjectPtr value(PyLong_FromLong(45));
48 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
49
50 const char* const keywords[] = {"first", "second", nullptr};
51 static _PyArg_Parser parser = {"ii:ParseTupleAndKeywordsFastFromTupleAndDict",
52 keywords};
53 int out1 = -1, out2 = -1;
54 EXPECT_EQ(
55 _PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out1, &out2), 1);
56 EXPECT_EQ(out1, 44);
57 EXPECT_EQ(out2, 45);
58}
59
60TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastWithOptionals) {
61 PyObjectPtr args(PyTuple_New(0));
62 PyObjectPtr kwargs(PyDict_New());
63 PyObjectPtr key(PyUnicode_FromString("second"));
64 PyObjectPtr value(PyLong_FromLong(42));
65 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
66
67 const char* const keywords[] = {"first", "second", nullptr};
68 static _PyArg_Parser parser = {"|ii:ParseTupleAndKeywordsFastWithOptionals",
69 keywords};
70 int out1 = -1, out2 = -1;
71 EXPECT_EQ(
72 _PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out1, &out2), 1);
73 EXPECT_EQ(out1, -1);
74 EXPECT_EQ(out2, 42);
75}
76
77TEST_F(GetArgsExtensionApiTest, ParseStackMaintainsRefcount) {
78 PyObjectPtr str(PyUnicode_FromString("hello world"));
79 Py_ssize_t old_refcnt = Py_REFCNT(str);
80 PyObject* args[] = {str};
81 PyObject* out = nullptr;
82 EXPECT_EQ(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O", &out), 1);
83 EXPECT_EQ(PyErr_Occurred(), nullptr);
84 EXPECT_EQ(out, str.get());
85 EXPECT_EQ(Py_REFCNT(out), old_refcnt);
86 _PyArg_Fini();
87}
88
89TEST_F(GetArgsExtensionApiTest, ParseStackOneObject) {
90 PyObjectPtr str(PyUnicode_FromString("hello world"));
91 PyObject* args[] = {str};
92 PyObject* out = nullptr;
93 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O:xyz", &out));
94 EXPECT_EQ(PyErr_Occurred(), nullptr);
95 EXPECT_EQ(out, str.get());
96}
97
98TEST_F(GetArgsExtensionApiTest, ParseStackMultipleObjects) {
99 PyObjectPtr long111(PyLong_FromLong(111));
100 PyObjectPtr long333(PyLong_FromLong(333));
101 PyObject* args[] = {long111, Py_None, long333};
102 PyObject* out1 = nullptr;
103 PyObject* out2 = nullptr;
104 PyObject* out3 = nullptr;
105 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "OOO:xyz", &out1,
106 &out2, &out3));
107 EXPECT_EQ(PyErr_Occurred(), nullptr);
108 EXPECT_EQ(out1, long111.get());
109 EXPECT_EQ(out2, Py_None);
110 EXPECT_EQ(out3, long333.get());
111}
112
113TEST_F(GetArgsExtensionApiTest, ParseStackUnicodeObject) {
114 PyObjectPtr str(PyUnicode_FromString("hello world"));
115 PyObject* args[] = {str};
116 PyObject* out = nullptr;
117 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "U:xyz", &out));
118 EXPECT_EQ(PyErr_Occurred(), nullptr);
119 EXPECT_EQ(out, str);
120}
121
122TEST_F(GetArgsExtensionApiTest, ParseStackWithWrongTypeRaisesTypeError) {
123 PyObjectPtr non_str(PyLong_FromLong(10));
124 PyObject* args[] = {non_str};
125 PyObject* out = nullptr;
126 EXPECT_FALSE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "U:xyz", &out));
127 ASSERT_NE(PyErr_Occurred(), nullptr);
128 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
129 EXPECT_EQ(out, nullptr);
130}
131
132TEST_F(GetArgsExtensionApiTest, ParseStackWithFormatsSAndZ) {
133 PyObjectPtr str1(PyUnicode_FromString("hello"));
134 PyObjectPtr str2(PyUnicode_FromString("world"));
135 PyObject* args[] = {str1, str2};
136 char* out1 = nullptr;
137 char* out2 = nullptr;
138 EXPECT_TRUE(
139 _PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "sz", &out1, &out2));
140 EXPECT_EQ(PyErr_Occurred(), nullptr);
141 EXPECT_STREQ("hello", out1);
142 EXPECT_STREQ("world", out2);
143}
144
145TEST_F(GetArgsExtensionApiTest, ParseStackWithStringAndNone) {
146 PyObject* args[] = {Py_None, Py_None};
147 char* out1 = nullptr;
148 char* out2 = nullptr;
149 int size = 123;
150 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "zz#", &out1,
151 &out2, &size));
152 EXPECT_EQ(PyErr_Occurred(), nullptr);
153 EXPECT_EQ(nullptr, out1);
154 EXPECT_EQ(nullptr, out2);
155 EXPECT_EQ(0, size);
156}
157
158TEST_F(GetArgsExtensionApiTest, ParseStackWithStringAndSize) {
159 PyObjectPtr str1(PyUnicode_FromString("hello"));
160 PyObjectPtr str2(PyUnicode_FromString("cpython"));
161 PyObject* args[] = {str1, str2};
162 char* out1 = nullptr;
163 char* out2 = nullptr;
164 int size1 = 123;
165 int size2 = 456;
166 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "s#z#", &out1,
167 &size1, &out2, &size2));
168 EXPECT_EQ(PyErr_Occurred(), nullptr);
169 EXPECT_STREQ("hello", out1);
170 EXPECT_EQ(5, size1);
171 EXPECT_STREQ("cpython", out2);
172 EXPECT_EQ(7, size2);
173}
174
175TEST_F(GetArgsExtensionApiTest, ParseStackNumbers) {
176 const int k_ints = 11;
177 PyObject* args[k_ints];
178 for (int i = 0; i < k_ints; i++) {
179 args[i] = PyLong_FromLong(123 + i);
180 }
181
182 unsigned char nb;
183 unsigned char n_b;
184 short int nh;
185 unsigned short int n_h;
186 int ni;
187 unsigned int n_i;
188 long int nl;
189 unsigned long nk;
190 long long n_l;
191 unsigned long long n_k;
192 Py_ssize_t nn;
193
194 EXPECT_TRUE(_PyArg_ParseStack(args, k_ints, "bBhHiIlkLKn", &nb, &n_b, &nh,
195 &n_h, &ni, &n_i, &nl, &nk, &n_l, &n_k, &nn));
196 EXPECT_EQ(PyErr_Occurred(), nullptr);
197 EXPECT_EQ(123, nb);
198 EXPECT_EQ(124, n_b);
199 EXPECT_EQ(125, nh);
200 EXPECT_EQ(126, n_h);
201 EXPECT_EQ(127, ni);
202 EXPECT_EQ(128U, n_i);
203 EXPECT_EQ(129, nl);
204 EXPECT_EQ(130UL, nk);
205 EXPECT_EQ(131, n_l);
206 EXPECT_EQ(132ULL, n_k);
207 EXPECT_EQ(133, nn);
208
209 for (int i = 0; i < k_ints; i++) {
210 Py_DECREF(args[i]);
211 }
212}
213
214TEST_F(GetArgsExtensionApiTest, ParseStackOptionalPresent) {
215 PyObjectPtr obj(PyLong_FromLong(111));
216 PyObject* args[] = {obj};
217
218 PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
219 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "|O", &out));
220 EXPECT_EQ(PyErr_Occurred(), nullptr);
221 EXPECT_EQ(out, obj.get());
222}
223
224TEST_F(GetArgsExtensionApiTest, ParseStackOptionalNotPresent) {
225 PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
226 EXPECT_TRUE(_PyArg_ParseStack(nullptr, 0, "|O", &out));
227 EXPECT_EQ(PyErr_Occurred(), nullptr);
228 ASSERT_EQ(out, reinterpret_cast<PyObject*>(0xdeadbeef));
229}
230
231TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithCorrectType) {
232 PyObjectPtr obj(PyLong_FromLong(111));
233 PyObject* args[] = {obj};
234
235 PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
236 EXPECT_TRUE(
237 _PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O!", &PyLong_Type, &out));
238 EXPECT_EQ(PyErr_Occurred(), nullptr);
239 EXPECT_EQ(out, obj.get());
240}
241
242TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithIncorrectType) {
243 PyObjectPtr obj(PyLong_FromLong(111));
244 PyObject* args[] = {obj};
245
246 PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
247 EXPECT_FALSE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O!",
248 &PyTuple_Type, &out));
249 ASSERT_NE(PyErr_Occurred(), nullptr);
250 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
251 EXPECT_EQ(out, reinterpret_cast<PyObject*>(0xdeadbeef));
252}
253
254TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithConverter) {
255 using converter_func = void (*)(PyObject*, void*);
256 converter_func converter = [](PyObject* ptr, void* out) {
257 *static_cast<int*>(out) = 1 + PyLong_AsLong(ptr);
258 };
259
260 PyObjectPtr obj(PyLong_FromLong(111));
261 PyObject* args[] = {obj};
262
263 int out = 0;
264 EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O&", converter,
265 static_cast<void*>(&out)));
266 EXPECT_EQ(out, 112);
267}
268
269TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsOneObject) {
270 PyObjectPtr long10(PyLong_FromLong(10));
271 PyObject* args[] = {long10};
272 int nargs = Py_ARRAY_LENGTH(args);
273
274 const char* const keywords[] = {"first", nullptr};
275 static _PyArg_Parser parser = {"O:ParseStackOneObject", keywords};
276
277 PyObject* kwnames = nullptr;
278 PyObject* out = nullptr;
279
280 EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out),
281 1);
282 EXPECT_EQ(PyLong_AsLong(out), 10);
283 _PyArg_Fini();
284}
285
286TEST_F(GetArgsExtensionApiTest,
287 ParseStackAndKeywordsWithLongKWNamesRaisesTypeError) {
288 PyObjectPtr long10(PyLong_FromLong(10));
289 PyObject* args[] = {long10};
290 int nargs = Py_ARRAY_LENGTH(args);
291
292 PyObjectPtr kwnames(PyTuple_New(1));
293 PyObject* in1 = PyLong_FromLong(37);
294 ASSERT_NE(-1, PyTuple_SetItem(kwnames, 0, in1));
295
296 const char* const keywords[] = {"first", "second", nullptr};
297 static _PyArg_Parser parser = {"OO:ParseStackWithLongKWNamesRaisesTypeError",
298 keywords};
299 PyObject* out1 = nullptr;
300
301 EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1),
302 0);
303 ASSERT_NE(PyErr_Occurred(), nullptr);
304 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
305 EXPECT_EQ(PyLong_AsLong(out1), 10);
306 _PyArg_Fini();
307}
308
309TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsMultipleObjects) {
310 PyObjectPtr long10(PyLong_FromLong(10));
311 PyObjectPtr long33(PyLong_FromLong(33));
312 PyObjectPtr test_str(PyUnicode_FromString("test_str"));
313 PyObject* args[] = {long10, long33, test_str};
314 int nargs = Py_ARRAY_LENGTH(args);
315
316 const char* const keywords[] = {"first", "second", "third", nullptr};
317 static _PyArg_Parser parser = {"OOU:ParseStackMultipleObjects", keywords};
318
319 PyObject* kwnames = nullptr;
320 PyObject* out1 = nullptr;
321 PyObject* out2 = nullptr;
322 PyObject* out3 = nullptr;
323
324 EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1,
325 &out2, &out3),
326 1);
327 EXPECT_EQ(PyLong_AsLong(out1), 10);
328 EXPECT_EQ(PyLong_AsLong(out2), 33);
329 EXPECT_EQ(out3, test_str);
330 _PyArg_Fini();
331}
332
333TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsUnicode) {
334 PyObjectPtr hello(PyUnicode_FromString("hello"));
335 PyObjectPtr world(PyUnicode_FromString("world"));
336 PyObject* args[] = {hello, world};
337 int nargs = Py_ARRAY_LENGTH(args);
338
339 const char* const keywords[] = {"first", "second", nullptr};
340 static _PyArg_Parser parser = {"UU:ParseStackUnicode", keywords};
341
342 PyObject* kwnames = nullptr;
343 PyObject* out1 = nullptr;
344 PyObject* out2 = nullptr;
345 EXPECT_EQ(
346 _PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1, &out2),
347 1);
348 EXPECT_EQ(hello, out1);
349 EXPECT_EQ(world, out2);
350 _PyArg_Fini();
351}
352
353TEST_F(GetArgsExtensionApiTest,
354 ParseStackAndKeywordsWithWrongTypeRaisesTypeError) {
355 PyObjectPtr long100(PyLong_FromLong(100));
356 PyObject* args[] = {long100};
357 int nargs = Py_ARRAY_LENGTH(args);
358
359 const char* const keywords[] = {"first", nullptr};
360 _PyArg_Parser parser = {"U:ParseStackWithWrongTypeRaisesTypeError", keywords};
361
362 PyObject* kwnames = nullptr;
363 PyObject* out1 = nullptr;
364 EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1),
365 0);
366 ASSERT_NE(PyErr_Occurred(), nullptr);
367 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
368 EXPECT_EQ(out1, nullptr);
369 _PyArg_Fini();
370}
371
372TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsString) {
373 PyObjectPtr hello(PyUnicode_FromString("hello"));
374 PyObjectPtr world(PyUnicode_FromString("world"));
375 PyObject* args[] = {hello, world};
376 int nargs = Py_ARRAY_LENGTH(args);
377
378 const char* const keywords[] = {"first", "second", nullptr};
379 _PyArg_Parser parser = {"sz:ParseStackString", keywords};
380
381 PyObject* kwnames = nullptr;
382 char* out1 = nullptr;
383 char* out2 = nullptr;
384 EXPECT_EQ(
385 _PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1, &out2),
386 1);
387 EXPECT_STREQ("hello", out1);
388 EXPECT_STREQ("world", out2);
389 _PyArg_Fini();
390}
391
392TEST_F(GetArgsExtensionApiTest, ParseTupleOneObject) {
393 PyObjectPtr pytuple(PyTuple_New(1));
394 PyObject* in = PyUnicode_FromString("hello world");
395 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
396
397 long refcnt = Py_REFCNT(in);
398 PyObject* out;
399 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "O:xyz", &out));
400 // This returns a borrowed reference, verify ref count did not change
401 EXPECT_EQ(Py_REFCNT(out), refcnt);
402 EXPECT_TRUE(_PyUnicode_EqualToASCIIString(out, "hello world"));
403}
404
405TEST_F(GetArgsExtensionApiTest, ParseTupleMultipleObjects) {
406 PyObjectPtr pytuple(PyTuple_New(3));
407 PyObject* in1 = PyLong_FromLong(111);
408 PyObject* in2 = Py_None;
409 Py_INCREF(in2);
410 PyObject* in3 = PyLong_FromLong(333);
411 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
412 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, in2));
413 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 2, in3));
414
415 PyObject* out1;
416 PyObject* out2;
417 PyObject* out3;
418 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "OOO:xyz", &out1, &out2, &out3));
419 EXPECT_EQ(111, PyLong_AsLong(out1));
420 EXPECT_EQ(Py_None, out2);
421 EXPECT_EQ(333, PyLong_AsLong(out3));
422}
423
424TEST_F(GetArgsExtensionApiTest, ParseTupleUnicodeObject) {
425 PyObjectPtr pytuple(PyTuple_New(1));
426 PyObject* in1 = PyUnicode_FromString("pyro");
427 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
428
429 PyObject* out1;
430 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "U:is_frozen", &out1));
431 EXPECT_EQ(in1, out1);
432}
433
434TEST_F(GetArgsExtensionApiTest, ParseTupleWithWrongType) {
435 PyObjectPtr pytuple(PyTuple_New(1));
436 PyObject* in = PyLong_FromLong(42);
437 ASSERT_NE(in, nullptr);
438 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
439
440 PyObject* out1 = nullptr;
441 EXPECT_FALSE(PyArg_ParseTuple(pytuple, "U:is_frozen", &out1));
442 EXPECT_NE(PyErr_Occurred(), nullptr);
443 EXPECT_EQ(out1, nullptr);
444}
445
446TEST_F(GetArgsExtensionApiTest, ParseTupleString) {
447 PyObjectPtr pytuple(PyTuple_New(2));
448 PyObject* in1 = PyUnicode_FromString("hello");
449 PyObject* in2 = PyUnicode_FromString("world");
450 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
451 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, in2));
452
453 char *out1, *out2;
454 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "sz", &out1, &out2));
455 EXPECT_STREQ("hello", out1);
456 EXPECT_STREQ("world", out2);
457}
458
459TEST_F(GetArgsExtensionApiTest, ParseTupleStringFromNone) {
460 PyObjectPtr pytuple(PyTuple_New(2));
461 Py_INCREF(Py_None);
462 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, Py_None));
463 Py_INCREF(Py_None);
464 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, Py_None));
465
466 char *out1, *out2;
467 int size = 123;
468 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "zz#", &out1, &out2, &size));
469 EXPECT_EQ(nullptr, out1);
470 EXPECT_EQ(nullptr, out2);
471 EXPECT_EQ(0, size);
472}
473
474TEST_F(GetArgsExtensionApiTest, ParseTupleStringWithSize) {
475 PyObjectPtr pytuple(PyTuple_New(2));
476 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyUnicode_FromString("hello")));
477 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, PyUnicode_FromString("cpython")));
478
479 char *out1, *out2;
480 int size1, size2;
481 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "s#z#", &out1, &size1, &out2, &size2));
482 EXPECT_STREQ("hello", out1);
483 EXPECT_EQ(5, size1);
484 EXPECT_STREQ("cpython", out2);
485 EXPECT_EQ(7, size2);
486}
487
488TEST_F(GetArgsExtensionApiTest, ParseTupleNumbers) {
489 const int k_ints = 11;
490 PyObjectPtr pytuple(PyTuple_New(k_ints));
491 for (int i = 0; i < k_ints; i++) {
492 ASSERT_EQ(0, PyTuple_SetItem(pytuple, i, PyLong_FromLong(123 + i)));
493 }
494
495 unsigned char nb, n_b;
496 short int nh;
497 unsigned short int n_h;
498 int ni;
499 unsigned int n_i;
500 long int nl;
501 unsigned long nk;
502 long long n_l;
503 unsigned long long n_k;
504 Py_ssize_t nn;
505
506 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "bBhHiIlkLKn", &nb, &n_b, &nh, &n_h,
507 &ni, &n_i, &nl, &nk, &n_l, &n_k, &nn));
508 EXPECT_EQ(123, nb);
509 EXPECT_EQ(124, n_b);
510 EXPECT_EQ(125, nh);
511 EXPECT_EQ(126, n_h);
512 EXPECT_EQ(127, ni);
513 EXPECT_EQ(128U, n_i);
514 EXPECT_EQ(129, nl);
515 EXPECT_EQ(130UL, nk);
516 EXPECT_EQ(131, n_l);
517 EXPECT_EQ(132ULL, n_k);
518 EXPECT_EQ(133, nn);
519}
520
521TEST_F(GetArgsExtensionApiTest, ParseTupleOptionalPresent) {
522 PyObjectPtr pytuple(PyTuple_New(1));
523 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyLong_FromLong(111)));
524
525 PyObject* out = nullptr;
526 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "|O", &out));
527 ASSERT_NE(out, nullptr);
528 EXPECT_EQ(111, PyLong_AsLong(out));
529}
530
531TEST_F(GetArgsExtensionApiTest, ParseTupleOptionalNotPresent) {
532 PyObjectPtr pytuple(PyTuple_New(0));
533
534 PyObject* out = nullptr;
535 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "|O", &out));
536 ASSERT_EQ(out, nullptr);
537}
538
539TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithCorrectType) {
540 PyObjectPtr pytuple(PyTuple_New(1));
541 PyObject* in = PyLong_FromLong(111);
542 PyTypeObject* type = Py_TYPE(in);
543 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
544
545 PyObject* out = nullptr;
546 EXPECT_TRUE(PyArg_ParseTuple(pytuple, "O!", type, &out));
547
548 EXPECT_EQ(PyErr_Occurred(), nullptr);
549 EXPECT_EQ(111, PyLong_AsLong(out));
550}
551
552TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithIncorrectType) {
553 PyObjectPtr pytuple(PyTuple_New(1));
554 PyObject* in = PyLong_FromLong(111);
555 PyTypeObject* type = Py_TYPE(pytuple);
556 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
557
558 PyObject* out = nullptr;
559 EXPECT_FALSE(PyArg_ParseTuple(pytuple, "O!", type, &out));
560
561 EXPECT_NE(PyErr_Occurred(), nullptr);
562 EXPECT_EQ(out, nullptr);
563}
564
565TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithConverter) {
566 using converter_func = void (*)(PyObject*, void*);
567 converter_func converter = [](PyObject* ptr, void* out) {
568 *static_cast<int*>(out) = 1 + PyLong_AsLong(ptr);
569 };
570
571 PyObjectPtr pytuple(PyTuple_New(1));
572 ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyLong_FromLong(111)));
573
574 int out = 0;
575 EXPECT_TRUE(
576 PyArg_ParseTuple(pytuple, "O&", converter, static_cast<void*>(&out)));
577 EXPECT_EQ(out, 112);
578}
579
580TEST_F(GetArgsExtensionApiTest, OldStyleParseWithInt) {
581 PyObjectPtr pylong(PyLong_FromLong(666));
582 int n = 0;
583 EXPECT_TRUE(PyArg_Parse(pylong, "i", &n));
584 EXPECT_EQ(n, 666);
585}
586
587TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromDict) {
588 PyObjectPtr args(PyTuple_New(0));
589 PyObjectPtr kwargs(PyDict_New());
590 PyObjectPtr key(PyUnicode_FromString("first"));
591 PyObjectPtr value(PyLong_FromLong(42));
592 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
593
594 const char* kwnames[] = {"first", nullptr};
595 int out = -1;
596 EXPECT_TRUE(PyArg_ParseTupleAndKeywords(args, kwargs, "i",
597 const_cast<char**>(kwnames), &out));
598 EXPECT_EQ(out, 42);
599}
600
601TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromTuple) {
602 PyObjectPtr args(PyTuple_New(1));
603 ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(43)));
604 PyObjectPtr kwargs(PyDict_New());
605
606 const char* kwnames[] = {"first", nullptr};
607 int out = -1;
608 EXPECT_TRUE(PyArg_ParseTupleAndKeywords(args, kwargs, "i",
609 const_cast<char**>(kwnames), &out));
610 EXPECT_EQ(out, 43);
611}
612
613TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromTupleAndDict) {
614 PyObjectPtr args(PyTuple_New(1));
615 ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(44)));
616 PyObjectPtr kwargs(PyDict_New());
617 PyObjectPtr key(PyUnicode_FromString("second"));
618 PyObjectPtr value(PyLong_FromLong(45));
619 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
620
621 const char* kwnames[] = {"first", "second", nullptr};
622 int out1 = -1, out2 = -1;
623 EXPECT_TRUE(PyArg_ParseTupleAndKeywords(
624 args, kwargs, "ii", const_cast<char**>(kwnames), &out1, &out2));
625 EXPECT_EQ(out1, 44);
626 EXPECT_EQ(out2, 45);
627}
628
629TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsWithOptionals) {
630 PyObjectPtr args(PyTuple_New(0));
631 PyObjectPtr kwargs(PyDict_New());
632 PyObjectPtr key(PyUnicode_FromString("second"));
633 PyObjectPtr value(PyLong_FromLong(42));
634 ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
635
636 const char* kwnames[] = {"first", "second", nullptr};
637 int out1 = -1, out2 = -1;
638 EXPECT_TRUE(PyArg_ParseTupleAndKeywords(
639 args, kwargs, "|ii", const_cast<char**>(kwnames), &out1, &out2));
640 EXPECT_EQ(out1, -1);
641 EXPECT_EQ(out2, 42);
642}
643
644#pragma push_macro("_PyArg_NoKeywords")
645#undef _PyArg_NoKeywords
646TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNullptrReturnsTrue) {
647 EXPECT_EQ(_PyArg_NoKeywords("", nullptr), 1);
648}
649#pragma pop_macro("_PyArg_NoKeywords")
650
651#pragma push_macro("_PyArg_NoKeywords")
652#undef _PyArg_NoKeywords
653TEST_F(GetArgsExtensionApiTest, NoKeywordsWithEmptyDictReturnsTrue) {
654 PyObjectPtr empty_dict(PyDict_New());
655 EXPECT_EQ(_PyArg_NoKeywords("", empty_dict), 1);
656}
657#pragma pop_macro("_PyArg_NoKeywords")
658
659#pragma push_macro("_PyArg_NoKeywords")
660#undef _PyArg_NoKeywords
661TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNonDictRaisesSystemError) {
662 PyObjectPtr not_a_dict(PyTuple_New(10));
663 EXPECT_EQ(_PyArg_NoKeywords("", not_a_dict), 0);
664 ASSERT_NE(PyErr_Occurred(), nullptr);
665 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
666}
667#pragma pop_macro("_PyArg_NoKeywords")
668
669#pragma push_macro("_PyArg_NoKeywords")
670#undef _PyArg_NoKeywords
671TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNonEmptyDictRaisesTypeError) {
672 PyObjectPtr non_empty_dict(PyDict_New());
673 PyObjectPtr tuple(PyTuple_New(0));
674 PyDict_SetItemString(non_empty_dict, "my key", tuple);
675 EXPECT_EQ(_PyArg_NoKeywords("", non_empty_dict.get()), 0);
676 ASSERT_NE(PyErr_Occurred(), nullptr);
677 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
678}
679#pragma pop_macro("_PyArg_NoKeywords")
680
681#pragma push_macro("_PyArg_NoPositional")
682#undef _PyArg_NoPositional
683TEST_F(GetArgsExtensionApiTest, NoPositionalWithNullptrReturnsTrue) {
684 EXPECT_EQ(_PyArg_NoPositional("", nullptr), 1);
685}
686#pragma pop_macro("_PyArg_NoPositional")
687
688#pragma push_macro("_PyArg_NoPositional")
689#undef _PyArg_NoPositional
690TEST_F(GetArgsExtensionApiTest, NoPositionalWitEmptyTupleReturnsTrue) {
691 PyObjectPtr empty_tuple(PyTuple_New(0));
692 EXPECT_EQ(_PyArg_NoPositional("", empty_tuple), 1);
693}
694#pragma pop_macro("_PyArg_NoPositional")
695
696#pragma push_macro("_PyArg_NoPositional")
697#undef _PyArg_NoPositional
698TEST_F(GetArgsExtensionApiTest, NoPositionalWithNonTupleRaisesSystemError) {
699 PyObjectPtr not_a_tuple(PyLong_FromLong(1));
700 EXPECT_EQ(_PyArg_NoPositional("", not_a_tuple), 0);
701 EXPECT_NE(PyErr_Occurred(), nullptr);
702 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
703}
704#pragma pop_macro("_PyArg_NoPositional")
705
706#pragma push_macro("_PyArg_NoPositional")
707#undef _PyArg_NoPositional
708TEST_F(GetArgsExtensionApiTest, NoPositionalWithNonEmptyTupleRaisesTypeError) {
709 PyObjectPtr non_empty_tuple(PyTuple_New(10));
710 EXPECT_EQ(_PyArg_NoPositional("", non_empty_tuple), 0);
711 ASSERT_NE(PyErr_Occurred(), nullptr);
712 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
713}
714#pragma pop_macro("_PyArg_NoPositional")
715
716TEST_F(GetArgsExtensionApiTest,
717 UnpackStackWithNullNameAndNargsLessThanMinRaisesTypeError) {
718 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/1, /*name=*/nullptr,
719 /*min=*/2, /*max=*/3),
720 0);
721 ASSERT_NE(PyErr_Occurred(), nullptr);
722 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
723}
724
725TEST_F(GetArgsExtensionApiTest,
726 UnpackStackWithNonNullNameAndNargsLessThanMinRaisesTypeError) {
727 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/1, /*name=*/"foo",
728 /*min=*/2, /*max=*/3),
729 0);
730 ASSERT_NE(PyErr_Occurred(), nullptr);
731 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
732}
733
734TEST_F(GetArgsExtensionApiTest, UnpackStackWithNargsEqualsZeroReturnsOne) {
735 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/0, /*name=*/"foo",
736 /*min=*/0, /*max=*/3),
737 1);
738 EXPECT_EQ(PyErr_Occurred(), nullptr);
739}
740
741TEST_F(GetArgsExtensionApiTest,
742 UnpackStackWithNullNameAndNargsGreaterThanMaxRaisesTypeError) {
743 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/2, /*name=*/nullptr,
744 /*min=*/0, /*max=*/1),
745 0);
746 ASSERT_NE(PyErr_Occurred(), nullptr);
747 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
748}
749
750TEST_F(GetArgsExtensionApiTest,
751 UnpackStackWithNonNullNameAndNargsGreaterThanMaxRaisesTypeError) {
752 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/2, /*name=*/"foo",
753 /*min=*/0, /*max=*/1),
754 0);
755 ASSERT_NE(PyErr_Occurred(), nullptr);
756 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
757}
758
759TEST_F(GetArgsExtensionApiTest, UnpackStackUnpacksArrayIntoVarargs) {
760 PyObjectPtr long10(PyLong_FromLong(10));
761 PyObjectPtr long33(PyLong_FromLong(33));
762 PyObjectPtr test_str(PyUnicode_FromString("test_str"));
763 PyObject* args[] = {long10, long33, test_str};
764 PyObject *arg0 = nullptr, *arg1 = nullptr, *arg2 = nullptr;
765 EXPECT_EQ(_PyArg_UnpackStack(/*args=*/args, /*nargs=*/3, /*name=*/nullptr,
766 /*min=*/0, /*max=*/3, &arg0, &arg1, &arg2),
767 1);
768 EXPECT_EQ(PyErr_Occurred(), nullptr);
769 EXPECT_EQ(arg0, long10.get());
770 EXPECT_EQ(arg1, long33.get());
771 EXPECT_EQ(arg2, test_str.get());
772}
773
774} // namespace testing
775} // namespace py