ext/Python/getargs-test.cpp (663 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "Python.h"
#include "capi-fixture.h"
#include "capi-testing.h"
namespace py {
namespace testing {
using GetArgsExtensionApiTest = ExtensionApi;
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromDict) {
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("first"));
PyObjectPtr value(PyLong_FromLong(42));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* const keywords[] = {"first", nullptr};
static _PyArg_Parser parser = {"O:ParseTupleAndKeywordsFastFromDict",
keywords};
PyObject* out = Py_None;
EXPECT_EQ(_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out), 1);
EXPECT_EQ(PyLong_AsLong(out), 42);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromTuple) {
PyObjectPtr args(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(43)));
PyObjectPtr kwargs(PyDict_New());
const char* const keywords[] = {"first", nullptr};
static _PyArg_Parser parser = {"O:ParseTupleAndKeywordsFastFromTuple",
keywords};
PyObject* out = Py_None;
EXPECT_EQ(_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out), 1);
EXPECT_EQ(PyLong_AsLong(out), 43);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastFromTupleAndDict) {
PyObjectPtr args(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(44)));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("second"));
PyObjectPtr value(PyLong_FromLong(45));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* const keywords[] = {"first", "second", nullptr};
static _PyArg_Parser parser = {"ii:ParseTupleAndKeywordsFastFromTupleAndDict",
keywords};
int out1 = -1, out2 = -1;
EXPECT_EQ(
_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out1, &out2), 1);
EXPECT_EQ(out1, 44);
EXPECT_EQ(out2, 45);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsFastWithOptionals) {
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("second"));
PyObjectPtr value(PyLong_FromLong(42));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* const keywords[] = {"first", "second", nullptr};
static _PyArg_Parser parser = {"|ii:ParseTupleAndKeywordsFastWithOptionals",
keywords};
int out1 = -1, out2 = -1;
EXPECT_EQ(
_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &parser, &out1, &out2), 1);
EXPECT_EQ(out1, -1);
EXPECT_EQ(out2, 42);
}
TEST_F(GetArgsExtensionApiTest, ParseStackMaintainsRefcount) {
PyObjectPtr str(PyUnicode_FromString("hello world"));
Py_ssize_t old_refcnt = Py_REFCNT(str);
PyObject* args[] = {str};
PyObject* out = nullptr;
EXPECT_EQ(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O", &out), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, str.get());
EXPECT_EQ(Py_REFCNT(out), old_refcnt);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest, ParseStackOneObject) {
PyObjectPtr str(PyUnicode_FromString("hello world"));
PyObject* args[] = {str};
PyObject* out = nullptr;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O:xyz", &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, str.get());
}
TEST_F(GetArgsExtensionApiTest, ParseStackMultipleObjects) {
PyObjectPtr long111(PyLong_FromLong(111));
PyObjectPtr long333(PyLong_FromLong(333));
PyObject* args[] = {long111, Py_None, long333};
PyObject* out1 = nullptr;
PyObject* out2 = nullptr;
PyObject* out3 = nullptr;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "OOO:xyz", &out1,
&out2, &out3));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out1, long111.get());
EXPECT_EQ(out2, Py_None);
EXPECT_EQ(out3, long333.get());
}
TEST_F(GetArgsExtensionApiTest, ParseStackUnicodeObject) {
PyObjectPtr str(PyUnicode_FromString("hello world"));
PyObject* args[] = {str};
PyObject* out = nullptr;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "U:xyz", &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, str);
}
TEST_F(GetArgsExtensionApiTest, ParseStackWithWrongTypeRaisesTypeError) {
PyObjectPtr non_str(PyLong_FromLong(10));
PyObject* args[] = {non_str};
PyObject* out = nullptr;
EXPECT_FALSE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "U:xyz", &out));
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
EXPECT_EQ(out, nullptr);
}
TEST_F(GetArgsExtensionApiTest, ParseStackWithFormatsSAndZ) {
PyObjectPtr str1(PyUnicode_FromString("hello"));
PyObjectPtr str2(PyUnicode_FromString("world"));
PyObject* args[] = {str1, str2};
char* out1 = nullptr;
char* out2 = nullptr;
EXPECT_TRUE(
_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "sz", &out1, &out2));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_STREQ("hello", out1);
EXPECT_STREQ("world", out2);
}
TEST_F(GetArgsExtensionApiTest, ParseStackWithStringAndNone) {
PyObject* args[] = {Py_None, Py_None};
char* out1 = nullptr;
char* out2 = nullptr;
int size = 123;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "zz#", &out1,
&out2, &size));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(nullptr, out1);
EXPECT_EQ(nullptr, out2);
EXPECT_EQ(0, size);
}
TEST_F(GetArgsExtensionApiTest, ParseStackWithStringAndSize) {
PyObjectPtr str1(PyUnicode_FromString("hello"));
PyObjectPtr str2(PyUnicode_FromString("cpython"));
PyObject* args[] = {str1, str2};
char* out1 = nullptr;
char* out2 = nullptr;
int size1 = 123;
int size2 = 456;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "s#z#", &out1,
&size1, &out2, &size2));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_STREQ("hello", out1);
EXPECT_EQ(5, size1);
EXPECT_STREQ("cpython", out2);
EXPECT_EQ(7, size2);
}
TEST_F(GetArgsExtensionApiTest, ParseStackNumbers) {
const int k_ints = 11;
PyObject* args[k_ints];
for (int i = 0; i < k_ints; i++) {
args[i] = PyLong_FromLong(123 + i);
}
unsigned char nb;
unsigned char n_b;
short int nh;
unsigned short int n_h;
int ni;
unsigned int n_i;
long int nl;
unsigned long nk;
long long n_l;
unsigned long long n_k;
Py_ssize_t nn;
EXPECT_TRUE(_PyArg_ParseStack(args, k_ints, "bBhHiIlkLKn", &nb, &n_b, &nh,
&n_h, &ni, &n_i, &nl, &nk, &n_l, &n_k, &nn));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(123, nb);
EXPECT_EQ(124, n_b);
EXPECT_EQ(125, nh);
EXPECT_EQ(126, n_h);
EXPECT_EQ(127, ni);
EXPECT_EQ(128U, n_i);
EXPECT_EQ(129, nl);
EXPECT_EQ(130UL, nk);
EXPECT_EQ(131, n_l);
EXPECT_EQ(132ULL, n_k);
EXPECT_EQ(133, nn);
for (int i = 0; i < k_ints; i++) {
Py_DECREF(args[i]);
}
}
TEST_F(GetArgsExtensionApiTest, ParseStackOptionalPresent) {
PyObjectPtr obj(PyLong_FromLong(111));
PyObject* args[] = {obj};
PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "|O", &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, obj.get());
}
TEST_F(GetArgsExtensionApiTest, ParseStackOptionalNotPresent) {
PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
EXPECT_TRUE(_PyArg_ParseStack(nullptr, 0, "|O", &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_EQ(out, reinterpret_cast<PyObject*>(0xdeadbeef));
}
TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithCorrectType) {
PyObjectPtr obj(PyLong_FromLong(111));
PyObject* args[] = {obj};
PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
EXPECT_TRUE(
_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O!", &PyLong_Type, &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, obj.get());
}
TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithIncorrectType) {
PyObjectPtr obj(PyLong_FromLong(111));
PyObject* args[] = {obj};
PyObject* out = reinterpret_cast<PyObject*>(0xdeadbeef);
EXPECT_FALSE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O!",
&PyTuple_Type, &out));
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
EXPECT_EQ(out, reinterpret_cast<PyObject*>(0xdeadbeef));
}
TEST_F(GetArgsExtensionApiTest, ParseStackObjectWithConverter) {
using converter_func = void (*)(PyObject*, void*);
converter_func converter = [](PyObject* ptr, void* out) {
*static_cast<int*>(out) = 1 + PyLong_AsLong(ptr);
};
PyObjectPtr obj(PyLong_FromLong(111));
PyObject* args[] = {obj};
int out = 0;
EXPECT_TRUE(_PyArg_ParseStack(args, Py_ARRAY_LENGTH(args), "O&", converter,
static_cast<void*>(&out)));
EXPECT_EQ(out, 112);
}
TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsOneObject) {
PyObjectPtr long10(PyLong_FromLong(10));
PyObject* args[] = {long10};
int nargs = Py_ARRAY_LENGTH(args);
const char* const keywords[] = {"first", nullptr};
static _PyArg_Parser parser = {"O:ParseStackOneObject", keywords};
PyObject* kwnames = nullptr;
PyObject* out = nullptr;
EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out),
1);
EXPECT_EQ(PyLong_AsLong(out), 10);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest,
ParseStackAndKeywordsWithLongKWNamesRaisesTypeError) {
PyObjectPtr long10(PyLong_FromLong(10));
PyObject* args[] = {long10};
int nargs = Py_ARRAY_LENGTH(args);
PyObjectPtr kwnames(PyTuple_New(1));
PyObject* in1 = PyLong_FromLong(37);
ASSERT_NE(-1, PyTuple_SetItem(kwnames, 0, in1));
const char* const keywords[] = {"first", "second", nullptr};
static _PyArg_Parser parser = {"OO:ParseStackWithLongKWNamesRaisesTypeError",
keywords};
PyObject* out1 = nullptr;
EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
EXPECT_EQ(PyLong_AsLong(out1), 10);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsMultipleObjects) {
PyObjectPtr long10(PyLong_FromLong(10));
PyObjectPtr long33(PyLong_FromLong(33));
PyObjectPtr test_str(PyUnicode_FromString("test_str"));
PyObject* args[] = {long10, long33, test_str};
int nargs = Py_ARRAY_LENGTH(args);
const char* const keywords[] = {"first", "second", "third", nullptr};
static _PyArg_Parser parser = {"OOU:ParseStackMultipleObjects", keywords};
PyObject* kwnames = nullptr;
PyObject* out1 = nullptr;
PyObject* out2 = nullptr;
PyObject* out3 = nullptr;
EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1,
&out2, &out3),
1);
EXPECT_EQ(PyLong_AsLong(out1), 10);
EXPECT_EQ(PyLong_AsLong(out2), 33);
EXPECT_EQ(out3, test_str);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsUnicode) {
PyObjectPtr hello(PyUnicode_FromString("hello"));
PyObjectPtr world(PyUnicode_FromString("world"));
PyObject* args[] = {hello, world};
int nargs = Py_ARRAY_LENGTH(args);
const char* const keywords[] = {"first", "second", nullptr};
static _PyArg_Parser parser = {"UU:ParseStackUnicode", keywords};
PyObject* kwnames = nullptr;
PyObject* out1 = nullptr;
PyObject* out2 = nullptr;
EXPECT_EQ(
_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1, &out2),
1);
EXPECT_EQ(hello, out1);
EXPECT_EQ(world, out2);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest,
ParseStackAndKeywordsWithWrongTypeRaisesTypeError) {
PyObjectPtr long100(PyLong_FromLong(100));
PyObject* args[] = {long100};
int nargs = Py_ARRAY_LENGTH(args);
const char* const keywords[] = {"first", nullptr};
_PyArg_Parser parser = {"U:ParseStackWithWrongTypeRaisesTypeError", keywords};
PyObject* kwnames = nullptr;
PyObject* out1 = nullptr;
EXPECT_EQ(_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
EXPECT_EQ(out1, nullptr);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest, ParseStackAndKeywordsString) {
PyObjectPtr hello(PyUnicode_FromString("hello"));
PyObjectPtr world(PyUnicode_FromString("world"));
PyObject* args[] = {hello, world};
int nargs = Py_ARRAY_LENGTH(args);
const char* const keywords[] = {"first", "second", nullptr};
_PyArg_Parser parser = {"sz:ParseStackString", keywords};
PyObject* kwnames = nullptr;
char* out1 = nullptr;
char* out2 = nullptr;
EXPECT_EQ(
_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &out1, &out2),
1);
EXPECT_STREQ("hello", out1);
EXPECT_STREQ("world", out2);
_PyArg_Fini();
}
TEST_F(GetArgsExtensionApiTest, ParseTupleOneObject) {
PyObjectPtr pytuple(PyTuple_New(1));
PyObject* in = PyUnicode_FromString("hello world");
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
long refcnt = Py_REFCNT(in);
PyObject* out;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "O:xyz", &out));
// This returns a borrowed reference, verify ref count did not change
EXPECT_EQ(Py_REFCNT(out), refcnt);
EXPECT_TRUE(_PyUnicode_EqualToASCIIString(out, "hello world"));
}
TEST_F(GetArgsExtensionApiTest, ParseTupleMultipleObjects) {
PyObjectPtr pytuple(PyTuple_New(3));
PyObject* in1 = PyLong_FromLong(111);
PyObject* in2 = Py_None;
Py_INCREF(in2);
PyObject* in3 = PyLong_FromLong(333);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, in2));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 2, in3));
PyObject* out1;
PyObject* out2;
PyObject* out3;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "OOO:xyz", &out1, &out2, &out3));
EXPECT_EQ(111, PyLong_AsLong(out1));
EXPECT_EQ(Py_None, out2);
EXPECT_EQ(333, PyLong_AsLong(out3));
}
TEST_F(GetArgsExtensionApiTest, ParseTupleUnicodeObject) {
PyObjectPtr pytuple(PyTuple_New(1));
PyObject* in1 = PyUnicode_FromString("pyro");
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
PyObject* out1;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "U:is_frozen", &out1));
EXPECT_EQ(in1, out1);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleWithWrongType) {
PyObjectPtr pytuple(PyTuple_New(1));
PyObject* in = PyLong_FromLong(42);
ASSERT_NE(in, nullptr);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
PyObject* out1 = nullptr;
EXPECT_FALSE(PyArg_ParseTuple(pytuple, "U:is_frozen", &out1));
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_EQ(out1, nullptr);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleString) {
PyObjectPtr pytuple(PyTuple_New(2));
PyObject* in1 = PyUnicode_FromString("hello");
PyObject* in2 = PyUnicode_FromString("world");
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in1));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, in2));
char *out1, *out2;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "sz", &out1, &out2));
EXPECT_STREQ("hello", out1);
EXPECT_STREQ("world", out2);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleStringFromNone) {
PyObjectPtr pytuple(PyTuple_New(2));
Py_INCREF(Py_None);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, Py_None));
Py_INCREF(Py_None);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, Py_None));
char *out1, *out2;
int size = 123;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "zz#", &out1, &out2, &size));
EXPECT_EQ(nullptr, out1);
EXPECT_EQ(nullptr, out2);
EXPECT_EQ(0, size);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleStringWithSize) {
PyObjectPtr pytuple(PyTuple_New(2));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyUnicode_FromString("hello")));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 1, PyUnicode_FromString("cpython")));
char *out1, *out2;
int size1, size2;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "s#z#", &out1, &size1, &out2, &size2));
EXPECT_STREQ("hello", out1);
EXPECT_EQ(5, size1);
EXPECT_STREQ("cpython", out2);
EXPECT_EQ(7, size2);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleNumbers) {
const int k_ints = 11;
PyObjectPtr pytuple(PyTuple_New(k_ints));
for (int i = 0; i < k_ints; i++) {
ASSERT_EQ(0, PyTuple_SetItem(pytuple, i, PyLong_FromLong(123 + i)));
}
unsigned char nb, n_b;
short int nh;
unsigned short int n_h;
int ni;
unsigned int n_i;
long int nl;
unsigned long nk;
long long n_l;
unsigned long long n_k;
Py_ssize_t nn;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "bBhHiIlkLKn", &nb, &n_b, &nh, &n_h,
&ni, &n_i, &nl, &nk, &n_l, &n_k, &nn));
EXPECT_EQ(123, nb);
EXPECT_EQ(124, n_b);
EXPECT_EQ(125, nh);
EXPECT_EQ(126, n_h);
EXPECT_EQ(127, ni);
EXPECT_EQ(128U, n_i);
EXPECT_EQ(129, nl);
EXPECT_EQ(130UL, nk);
EXPECT_EQ(131, n_l);
EXPECT_EQ(132ULL, n_k);
EXPECT_EQ(133, nn);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleOptionalPresent) {
PyObjectPtr pytuple(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyLong_FromLong(111)));
PyObject* out = nullptr;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "|O", &out));
ASSERT_NE(out, nullptr);
EXPECT_EQ(111, PyLong_AsLong(out));
}
TEST_F(GetArgsExtensionApiTest, ParseTupleOptionalNotPresent) {
PyObjectPtr pytuple(PyTuple_New(0));
PyObject* out = nullptr;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "|O", &out));
ASSERT_EQ(out, nullptr);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithCorrectType) {
PyObjectPtr pytuple(PyTuple_New(1));
PyObject* in = PyLong_FromLong(111);
PyTypeObject* type = Py_TYPE(in);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
PyObject* out = nullptr;
EXPECT_TRUE(PyArg_ParseTuple(pytuple, "O!", type, &out));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(111, PyLong_AsLong(out));
}
TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithIncorrectType) {
PyObjectPtr pytuple(PyTuple_New(1));
PyObject* in = PyLong_FromLong(111);
PyTypeObject* type = Py_TYPE(pytuple);
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, in));
PyObject* out = nullptr;
EXPECT_FALSE(PyArg_ParseTuple(pytuple, "O!", type, &out));
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_EQ(out, nullptr);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleObjectWithConverter) {
using converter_func = void (*)(PyObject*, void*);
converter_func converter = [](PyObject* ptr, void* out) {
*static_cast<int*>(out) = 1 + PyLong_AsLong(ptr);
};
PyObjectPtr pytuple(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(pytuple, 0, PyLong_FromLong(111)));
int out = 0;
EXPECT_TRUE(
PyArg_ParseTuple(pytuple, "O&", converter, static_cast<void*>(&out)));
EXPECT_EQ(out, 112);
}
TEST_F(GetArgsExtensionApiTest, OldStyleParseWithInt) {
PyObjectPtr pylong(PyLong_FromLong(666));
int n = 0;
EXPECT_TRUE(PyArg_Parse(pylong, "i", &n));
EXPECT_EQ(n, 666);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromDict) {
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("first"));
PyObjectPtr value(PyLong_FromLong(42));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* kwnames[] = {"first", nullptr};
int out = -1;
EXPECT_TRUE(PyArg_ParseTupleAndKeywords(args, kwargs, "i",
const_cast<char**>(kwnames), &out));
EXPECT_EQ(out, 42);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromTuple) {
PyObjectPtr args(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(43)));
PyObjectPtr kwargs(PyDict_New());
const char* kwnames[] = {"first", nullptr};
int out = -1;
EXPECT_TRUE(PyArg_ParseTupleAndKeywords(args, kwargs, "i",
const_cast<char**>(kwnames), &out));
EXPECT_EQ(out, 43);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsParseFromTupleAndDict) {
PyObjectPtr args(PyTuple_New(1));
ASSERT_NE(-1, PyTuple_SetItem(args, 0, PyLong_FromLong(44)));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("second"));
PyObjectPtr value(PyLong_FromLong(45));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* kwnames[] = {"first", "second", nullptr};
int out1 = -1, out2 = -1;
EXPECT_TRUE(PyArg_ParseTupleAndKeywords(
args, kwargs, "ii", const_cast<char**>(kwnames), &out1, &out2));
EXPECT_EQ(out1, 44);
EXPECT_EQ(out2, 45);
}
TEST_F(GetArgsExtensionApiTest, ParseTupleAndKeywordsWithOptionals) {
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr key(PyUnicode_FromString("second"));
PyObjectPtr value(PyLong_FromLong(42));
ASSERT_EQ(PyDict_SetItem(kwargs, key, value), 0);
const char* kwnames[] = {"first", "second", nullptr};
int out1 = -1, out2 = -1;
EXPECT_TRUE(PyArg_ParseTupleAndKeywords(
args, kwargs, "|ii", const_cast<char**>(kwnames), &out1, &out2));
EXPECT_EQ(out1, -1);
EXPECT_EQ(out2, 42);
}
#pragma push_macro("_PyArg_NoKeywords")
#undef _PyArg_NoKeywords
TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNullptrReturnsTrue) {
EXPECT_EQ(_PyArg_NoKeywords("", nullptr), 1);
}
#pragma pop_macro("_PyArg_NoKeywords")
#pragma push_macro("_PyArg_NoKeywords")
#undef _PyArg_NoKeywords
TEST_F(GetArgsExtensionApiTest, NoKeywordsWithEmptyDictReturnsTrue) {
PyObjectPtr empty_dict(PyDict_New());
EXPECT_EQ(_PyArg_NoKeywords("", empty_dict), 1);
}
#pragma pop_macro("_PyArg_NoKeywords")
#pragma push_macro("_PyArg_NoKeywords")
#undef _PyArg_NoKeywords
TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNonDictRaisesSystemError) {
PyObjectPtr not_a_dict(PyTuple_New(10));
EXPECT_EQ(_PyArg_NoKeywords("", not_a_dict), 0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
#pragma pop_macro("_PyArg_NoKeywords")
#pragma push_macro("_PyArg_NoKeywords")
#undef _PyArg_NoKeywords
TEST_F(GetArgsExtensionApiTest, NoKeywordsWithNonEmptyDictRaisesTypeError) {
PyObjectPtr non_empty_dict(PyDict_New());
PyObjectPtr tuple(PyTuple_New(0));
PyDict_SetItemString(non_empty_dict, "my key", tuple);
EXPECT_EQ(_PyArg_NoKeywords("", non_empty_dict.get()), 0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
#pragma pop_macro("_PyArg_NoKeywords")
#pragma push_macro("_PyArg_NoPositional")
#undef _PyArg_NoPositional
TEST_F(GetArgsExtensionApiTest, NoPositionalWithNullptrReturnsTrue) {
EXPECT_EQ(_PyArg_NoPositional("", nullptr), 1);
}
#pragma pop_macro("_PyArg_NoPositional")
#pragma push_macro("_PyArg_NoPositional")
#undef _PyArg_NoPositional
TEST_F(GetArgsExtensionApiTest, NoPositionalWitEmptyTupleReturnsTrue) {
PyObjectPtr empty_tuple(PyTuple_New(0));
EXPECT_EQ(_PyArg_NoPositional("", empty_tuple), 1);
}
#pragma pop_macro("_PyArg_NoPositional")
#pragma push_macro("_PyArg_NoPositional")
#undef _PyArg_NoPositional
TEST_F(GetArgsExtensionApiTest, NoPositionalWithNonTupleRaisesSystemError) {
PyObjectPtr not_a_tuple(PyLong_FromLong(1));
EXPECT_EQ(_PyArg_NoPositional("", not_a_tuple), 0);
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
#pragma pop_macro("_PyArg_NoPositional")
#pragma push_macro("_PyArg_NoPositional")
#undef _PyArg_NoPositional
TEST_F(GetArgsExtensionApiTest, NoPositionalWithNonEmptyTupleRaisesTypeError) {
PyObjectPtr non_empty_tuple(PyTuple_New(10));
EXPECT_EQ(_PyArg_NoPositional("", non_empty_tuple), 0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
#pragma pop_macro("_PyArg_NoPositional")
TEST_F(GetArgsExtensionApiTest,
UnpackStackWithNullNameAndNargsLessThanMinRaisesTypeError) {
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/1, /*name=*/nullptr,
/*min=*/2, /*max=*/3),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(GetArgsExtensionApiTest,
UnpackStackWithNonNullNameAndNargsLessThanMinRaisesTypeError) {
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/1, /*name=*/"foo",
/*min=*/2, /*max=*/3),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(GetArgsExtensionApiTest, UnpackStackWithNargsEqualsZeroReturnsOne) {
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/0, /*name=*/"foo",
/*min=*/0, /*max=*/3),
1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(GetArgsExtensionApiTest,
UnpackStackWithNullNameAndNargsGreaterThanMaxRaisesTypeError) {
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/2, /*name=*/nullptr,
/*min=*/0, /*max=*/1),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(GetArgsExtensionApiTest,
UnpackStackWithNonNullNameAndNargsGreaterThanMaxRaisesTypeError) {
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/nullptr, /*nargs=*/2, /*name=*/"foo",
/*min=*/0, /*max=*/1),
0);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(GetArgsExtensionApiTest, UnpackStackUnpacksArrayIntoVarargs) {
PyObjectPtr long10(PyLong_FromLong(10));
PyObjectPtr long33(PyLong_FromLong(33));
PyObjectPtr test_str(PyUnicode_FromString("test_str"));
PyObject* args[] = {long10, long33, test_str};
PyObject *arg0 = nullptr, *arg1 = nullptr, *arg2 = nullptr;
EXPECT_EQ(_PyArg_UnpackStack(/*args=*/args, /*nargs=*/3, /*name=*/nullptr,
/*min=*/0, /*max=*/3, &arg0, &arg1, &arg2),
1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(arg0, long10.get());
EXPECT_EQ(arg1, long33.get());
EXPECT_EQ(arg2, test_str.get());
}
} // namespace testing
} // namespace py