ext/Objects/abstract-test.cpp (3,848 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include <climits>
#include <cstring>
#include "Python.h"
#include "gtest/gtest.h"
#include "capi-fixture.h"
#include "capi-testing.h"
namespace py {
namespace testing {
using AbstractExtensionApiTest = ExtensionApi;
// Buffer Protocol
TEST_F(AbstractExtensionApiTest, PyBufferFillInfoSimpleFillsInfo) {
Py_buffer buffer;
char buf[13];
PyObjectPtr pyobj(PyTuple_New(1));
long prev_refcount = Py_REFCNT(pyobj);
int readonly = 1;
int result = PyBuffer_FillInfo(&buffer, pyobj, buf, sizeof(buf), readonly,
PyBUF_SIMPLE);
EXPECT_EQ(result, 0);
EXPECT_EQ(Py_REFCNT(pyobj), prev_refcount + 1);
EXPECT_EQ(buffer.obj, pyobj);
EXPECT_EQ(buffer.buf, buf);
EXPECT_EQ(buffer.len, (Py_ssize_t)sizeof(buf));
EXPECT_EQ(buffer.readonly, 1);
EXPECT_EQ(buffer.itemsize, 1);
EXPECT_EQ(buffer.format, nullptr);
EXPECT_EQ(buffer.ndim, 1);
EXPECT_EQ(buffer.shape, nullptr);
EXPECT_EQ(buffer.strides, nullptr);
EXPECT_EQ(buffer.suboffsets, nullptr);
EXPECT_EQ(buffer.internal, nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyBufferFillInfoWithWritableFormatNdStridesFillsInfo) {
Py_buffer buffer;
char buf[7];
PyObjectPtr pyobj(PyTuple_New(1));
long prev_refcount = Py_REFCNT(pyobj);
int readonly = 0;
int result = PyBuffer_FillInfo(
&buffer, pyobj, buf, sizeof(buf), readonly,
PyBUF_WRITABLE | PyBUF_FORMAT | PyBUF_ND | PyBUF_STRIDES);
EXPECT_EQ(result, 0);
EXPECT_EQ(Py_REFCNT(pyobj), prev_refcount + 1);
EXPECT_EQ(buffer.obj, pyobj);
EXPECT_EQ(buffer.buf, buf);
EXPECT_EQ(buffer.len, (Py_ssize_t)sizeof(buf));
EXPECT_EQ(buffer.readonly, 0);
EXPECT_EQ(buffer.itemsize, 1);
EXPECT_EQ(strcmp(buffer.format, "B"), 0);
EXPECT_EQ(buffer.ndim, 1);
EXPECT_EQ(buffer.shape, &buffer.len);
EXPECT_EQ(buffer.strides, &buffer.itemsize);
EXPECT_EQ(buffer.suboffsets, nullptr);
EXPECT_EQ(buffer.internal, nullptr);
}
TEST_F(AbstractExtensionApiTest, PyBufferFillInfoWithNullptrRaisesBufferError) {
int result = PyBuffer_FillInfo(nullptr, Py_None, nullptr, 0, 1, PyBUF_SIMPLE);
EXPECT_EQ(result, -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_BufferError));
}
TEST_F(AbstractExtensionApiTest,
PyBufferFillInfoWithWritableFlagAndReadonlyRaisesBufferError) {
Py_buffer buffer;
int result =
PyBuffer_FillInfo(&buffer, Py_None, nullptr, 0, 1, PyBUF_WRITABLE);
EXPECT_EQ(result, -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_BufferError));
}
TEST_F(AbstractExtensionApiTest,
PyBufferIsContiguousWithInvalidOrderReturnsFalse) {
Py_buffer buffer;
char data[1];
ASSERT_EQ(PyBuffer_FillInfo(&buffer, Py_None, data, /*len=*/1,
/*readonly=*/1, PyBUF_SIMPLE),
0);
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, '%'));
}
TEST_F(AbstractExtensionApiTest,
PyBufferIsContiguousWithSubOffsetsReturnsFalse) {
Py_buffer buffer;
char data[1];
ASSERT_EQ(PyBuffer_FillInfo(&buffer, Py_None, data, /*len=*/1,
/*readonly=*/1, PyBUF_SIMPLE),
0);
static Py_ssize_t suboffsets[] = {13};
buffer.suboffsets = suboffsets;
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, 'C'));
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, 'F'));
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, 'A'));
}
TEST_F(AbstractExtensionApiTest, PyBufferIsContiguousReturnsTrue) {
Py_buffer buffer;
char data[1];
ASSERT_EQ(PyBuffer_FillInfo(&buffer, Py_None, data, /*len=*/1,
/*readonly=*/1, PyBUF_SIMPLE),
0);
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'C'));
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'F'));
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'A'));
}
TEST_F(AbstractExtensionApiTest, PyBufferIsContiguousWithRowMajorBuffer) {
Py_buffer buffer;
char data[300];
ASSERT_EQ(PyBuffer_FillInfo(&buffer, Py_None, data, /*len=*/100,
/*readonly=*/1, PyBUF_STRIDES),
0);
buffer.itemsize = 2;
buffer.format = const_cast<char*>("h");
buffer.ndim = 3;
Py_ssize_t shape[3] = {10, 3, 5};
buffer.shape = shape;
Py_ssize_t strides[3] = {30, 10, 2};
buffer.strides = strides;
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'C'));
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, 'F'));
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'A'));
}
TEST_F(AbstractExtensionApiTest, PyBufferIsContiguousWithColumnMajorBuffer) {
Py_buffer buffer;
char data[420];
ASSERT_EQ(PyBuffer_FillInfo(&buffer, Py_None, data, /*len=*/100,
/*readonly=*/1, PyBUF_STRIDES),
0);
buffer.itemsize = 4;
buffer.format = const_cast<char*>("L");
buffer.ndim = 3;
Py_ssize_t shape[3] = {7, 3, 5};
buffer.shape = shape;
Py_ssize_t strides[3] = {4, 28, 84};
buffer.strides = strides;
EXPECT_FALSE(PyBuffer_IsContiguous(&buffer, 'C'));
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'F'));
EXPECT_TRUE(PyBuffer_IsContiguous(&buffer, 'A'));
}
TEST_F(AbstractExtensionApiTest, PyEvalCallFunctionCalls) {
PyRun_SimpleString(R"(
def func(*args):
return f"{args!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(PyEval_CallFunction(func, "(iI)s#i", 3, 7, "aaaa", 3, 99));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "((3, 7), 'aaa', 99)"));
}
TEST_F(AbstractExtensionApiTest, PyEvalCallMethodCalls) {
PyRun_SimpleString(R"(
class C:
x = 42
def func(self, *args):
return f"{self.x}{args!r}"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyEval_CallMethod(c, "func", "s#(i)", "ccc", 1, 7));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "42('c', (7,))"));
}
// PyIndex_Check
TEST_F(AbstractExtensionApiTest, PyIndexCheckWithIntReturnsTrue) {
PyObjectPtr int_num(PyLong_FromLong(1));
EXPECT_TRUE(PyIndex_Check(int_num.get()));
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyIndexCheckWithFloatReturnsFalse) {
PyObjectPtr float_num(PyFloat_FromDouble(1.1));
EXPECT_FALSE(PyIndex_Check(float_num.get()));
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyIndexCheckWithUncallableDunderIndexReturnsTrue) {
PyRun_SimpleString(R"(
class C:
__index__ = None
idx = C()
)");
PyObjectPtr idx(mainModuleGet("idx"));
EXPECT_TRUE(PyIndex_Check(idx.get()));
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyIndexCheckWithDunderIndexReturnsTrue) {
PyRun_SimpleString(R"(
class C:
def __index__(self):
return 1
idx = C()
)");
PyObjectPtr idx(mainModuleGet("idx"));
EXPECT_TRUE(PyIndex_Check(idx.get()));
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyIndexCheckWithDunderIndexDescriptorThatRaisesReturnsTrue) {
PyRun_SimpleString(R"(
class Desc:
def __get__(self, obj, type):
raise UserWarning("foo")
class C:
__index__ = Desc()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyIndex_Check(c.get()), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
// PyIter_Next
TEST_F(AbstractExtensionApiTest, PyIterNextReturnsNext) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr three(PyLong_FromLong(3));
PyObjectPtr tuple(PyTuple_Pack(3, one.get(), two.get(), three.get()));
PyObjectPtr iter(PyObject_GetIter(tuple));
ASSERT_NE(iter, nullptr);
PyObjectPtr next(PyIter_Next(iter));
ASSERT_NE(next, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(next), 1);
next = PyIter_Next(iter);
ASSERT_NE(next, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(next), 2);
next = PyIter_Next(iter);
ASSERT_NE(next, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(next), 3);
next = PyIter_Next(iter);
ASSERT_EQ(next, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyIterNextOnNonIterRaises) {
ASSERT_EQ(PyObject_GetIter(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyIterNextPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
return self
def __next__(self):
raise ValueError("hi")
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr iter(PyObject_GetIter(c));
ASSERT_NE(iter, nullptr);
PyObjectPtr next(PyIter_Next(iter));
ASSERT_EQ(next, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
// Mapping Protocol
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithoutGetItemReturnsFalse) {
PyRun_SimpleString(R"(
class ClassWithoutDunderGetItem: pass
obj = ClassWithoutDunderGetItem()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_FALSE(PyMapping_Check(obj));
}
TEST_F(AbstractExtensionApiTest,
PyMappingCheckWithoutGetItemOnClassReturnsFalse) {
PyRun_SimpleString(R"(
class ClassWithoutDunderGetItem: pass
obj = ClassWithoutDunderGetItem()
obj.__getitem__ = lambda self, key: 1
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_FALSE(PyMapping_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithNumericReturnsFalse) {
PyObjectPtr num(PyLong_FromLong(4));
EXPECT_FALSE(PyMapping_Check(num));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithSetReturnsFalse) {
PyObjectPtr set(PySet_New(nullptr));
EXPECT_FALSE(PyMapping_Check(set));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithBooleanReturnsFalse) {
EXPECT_FALSE(PyMapping_Check(Py_False));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithGetItemMethodReturnsTrue) {
PyRun_SimpleString(R"(
class ClassWithDunderGetItemMethod:
def __getitem__(self, key):
return None
obj = ClassWithDunderGetItemMethod()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_TRUE(PyMapping_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithGetItemAttrReturnsTrue) {
PyRun_SimpleString(R"(
class ClassWithDunderGetItemAttr:
__getitem__ = 42
obj = ClassWithDunderGetItemAttr()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_TRUE(PyMapping_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithStringReturnsTrue) {
PyObjectPtr str(PyUnicode_FromString("foo"));
EXPECT_TRUE(PyMapping_Check(str));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithListReturnsTrue) {
PyObjectPtr list(PyList_New(3));
EXPECT_TRUE(PyMapping_Check(list));
}
TEST_F(AbstractExtensionApiTest, PyMappingCheckWithDictReturnsTrue) {
PyObjectPtr dict(PyDict_New());
EXPECT_TRUE(PyMapping_Check(dict));
}
TEST_F(AbstractExtensionApiTest, PyMappingLengthOnNullRaisesSystemError) {
EXPECT_EQ(PyMapping_Length(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyMappingLengthWithNonMappingReturnsLen) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return 1
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyMapping_Length(obj), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyMappingSizeOnNullRaisesSystemError) {
EXPECT_EQ(PyMapping_Size(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
// Number Protocol
TEST_F(AbstractExtensionApiTest, PyNumberAbsoluteWithNullRaisesSystemError) {
ASSERT_EQ(PyNumber_Absolute(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PyNumberAbsoluteWithNoDunderAbsRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyNumber_Absolute(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberAbsoluteCallsDunderAbs) {
PyObjectPtr negative(PyLong_FromLong(-10));
PyObjectPtr positive(PyLong_FromLong(10));
PyObjectPtr result(PyNumber_Absolute(negative));
EXPECT_EQ(result, positive);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberAddWithNoDunderAddRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyNumber_Add(c, c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberAddCallsDunderAdd) {
PyRun_SimpleString(R"(
class ClassWithDunderAdd:
def __add__(self, other):
return "hello";
x = ClassWithDunderAdd()
)");
PyObjectPtr x(mainModuleGet("x"));
PyObjectPtr y(PyLong_FromLong(7));
PyObjectPtr result(PyNumber_Add(x, y));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "hello"));
}
TEST_F(AbstractExtensionApiTest, PyNumberAddWithIntsReturnsSum) {
PyObjectPtr x(PyLong_FromLong(7));
PyObjectPtr y(PyLong_FromLong(10));
PyObjectPtr result(PyNumber_Add(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 17);
}
TEST_F(AbstractExtensionApiTest, PyNumberAddWithUnicodeReturnsConcat) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyUnicode_FromString("bar"));
PyObjectPtr result(PyNumber_Add(x, y));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "foobar"));
}
TEST_F(AbstractExtensionApiTest, PyNumberAndWithNonIntRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_And(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberAndWithIntsReturnsBitwiseAnd) {
PyObjectPtr x(PyLong_FromLong(5)); // 0b0101
PyObjectPtr y(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_And(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1); // 0b0001
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithNullRaisesSystemError) {
ASSERT_EQ(PyNumber_AsSsize_t(nullptr, PyExc_TypeError), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithStringRaisesTypeError) {
PyObjectPtr str(PyUnicode_FromString("foo"));
ASSERT_EQ(PyNumber_AsSsize_t(str, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithIntReturnsInt) {
PyObjectPtr num(PyLong_FromLong(10));
Py_ssize_t result = PyNumber_AsSsize_t(num, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, 10);
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithIntSubclassReturnsInt) {
PyRun_SimpleString(R"(
class C(int):
def __index__(self): return 10
obj = C(42);
)");
PyObjectPtr obj(mainModuleGet("obj"));
Py_ssize_t result = PyNumber_AsSsize_t(obj, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithDunderIndexReturnsInt) {
PyRun_SimpleString(R"(
class C:
def __index__(self): return 42
obj = C();
)");
PyObjectPtr obj(mainModuleGet("obj"));
Py_ssize_t result = PyNumber_AsSsize_t(obj, nullptr);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, 42);
}
TEST_F(AbstractExtensionApiTest,
PyNumberAsSsizeTWithNegativeOneReturnsNegativeOne) {
PyObjectPtr num(PyLong_FromLong(-1));
Py_ssize_t result = PyNumber_AsSsize_t(num, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, -1);
}
TEST_F(AbstractExtensionApiTest,
PyNumberAsSsizeTWithOverflowAndNullClearsError) {
const unsigned char bytes[] = {0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
PyObjectPtr num(_PyLong_FromByteArray(bytes, sizeof(bytes), false, true));
Py_ssize_t result = PyNumber_AsSsize_t(num, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, 0x7fffffffffffffff);
}
TEST_F(AbstractExtensionApiTest,
PyNumberAsSsizeTWithUnderflowAndNullClearsError) {
const unsigned char bytes[] = {0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
PyObjectPtr num(_PyLong_FromByteArray(bytes, sizeof(bytes), false, true));
Py_ssize_t result = PyNumber_AsSsize_t(num, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, INT64_MIN);
}
TEST_F(AbstractExtensionApiTest, PyNumberAsSsizeTWithOverflowSetsGivenError) {
const unsigned char bytes[] = {0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
PyObjectPtr num(_PyLong_FromByteArray(bytes, sizeof(bytes), false, true));
ASSERT_EQ(PyNumber_AsSsize_t(num, PyExc_ModuleNotFoundError), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ModuleNotFoundError));
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithFloatReturnsTrue) {
PyObjectPtr float_num(PyFloat_FromDouble(1.1));
EXPECT_EQ(PyNumber_Check(float_num), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithIntReturnsTrue) {
PyObjectPtr int_num(PyLong_FromLong(1));
EXPECT_EQ(PyNumber_Check(int_num), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithFloatSubclassReturnsTrue) {
PyRun_SimpleString(R"(
class SubFloat(float):
pass
sub = SubFloat()
)");
PyObjectPtr sub(mainModuleGet("sub"));
EXPECT_EQ(PyNumber_Check(sub), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithDunderIntClassReturnsTrue) {
PyRun_SimpleString(R"(
class DunderIntClass():
def __int__(self):
return 5
i = DunderIntClass()
)");
PyObjectPtr i(mainModuleGet("i"));
EXPECT_EQ(PyNumber_Check(i), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithDunderFloatClassReturnsTrue) {
PyRun_SimpleString(R"(
class DunderFloatClass():
def __float__(self):
return 5.0
f = DunderFloatClass()
)");
PyObjectPtr f(mainModuleGet("f"));
EXPECT_EQ(PyNumber_Check(f), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithNonNumberReturnsFalse) {
PyObjectPtr str(PyUnicode_FromString(""));
EXPECT_EQ(PyNumber_Check(str), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyNumberCheckWithDunderIntDescriptorThatRaisesReturnsTrue) {
PyRun_SimpleString(R"(
class Desc:
def __get__(self, obj, type):
raise UserWarning("foo")
class C:
__int__ = Desc()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyNumber_Check(c), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyNumberCheckWithDunderFloatDescriptorThatRaisesReturnsTrue) {
PyRun_SimpleString(R"(
class Desc:
def __get__(self, obj, type):
raise UserWarning("foo")
class C:
__float__ = Desc()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyNumber_Check(c), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberCheckWithNullReturnsFalse) {
EXPECT_EQ(PyNumber_Check(nullptr), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberFloatWithNullRaisesSystemError) {
EXPECT_EQ(PyNumber_Float(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberFloatWithStringReturnsFloat) {
PyObjectPtr str(PyUnicode_FromString("4.2"));
PyObjectPtr flt(PyNumber_Float(str));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyFloat_CheckExact(flt));
EXPECT_EQ(PyFloat_AsDouble(flt), 4.2);
}
TEST_F(AbstractExtensionApiTest, PyNumberFloatWithIntReturnsFloat) {
PyObjectPtr num(PyLong_FromLong(42));
PyObjectPtr flt(PyNumber_Float(num));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyFloat_CheckExact(flt));
EXPECT_EQ(PyFloat_AsDouble(flt), 42.0);
}
TEST_F(AbstractExtensionApiTest, PyNumberFloatWithFloatReturnsSameFloat) {
PyObjectPtr num(PyFloat_FromDouble(4.2));
Py_ssize_t refcnt = Py_REFCNT(num);
PyObjectPtr flt(PyNumber_Float(num));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(num, flt);
EXPECT_EQ(Py_REFCNT(num), refcnt + 1);
}
TEST_F(AbstractExtensionApiTest, PyNumberFloatWithFloatSubclassReturnsFloat) {
PyRun_SimpleString(R"(
class C(float):
pass
x = C(4.2)
)");
PyObjectPtr x(mainModuleGet("x"));
PyObjectPtr flt(PyNumber_Float(x));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyFloat_CheckExact(flt));
EXPECT_EQ(PyFloat_AsDouble(flt), 4.2);
}
TEST_F(AbstractExtensionApiTest,
PyNumberFloatWithDescriptorThatRaisesPropagatesException) {
PyRun_SimpleString(R"(
class Desc:
def __get__(self, obj, type):
raise UserWarning("foo")
class C:
__float__ = Desc()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyNumber_Float(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyNumberFloorDivideWithNonIntRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_FloorDivide(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberFloorDivideWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyLong_FromLong(5));
PyObjectPtr result(PyNumber_FloorDivide(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 8);
}
TEST_F(AbstractExtensionApiTest, PyNumberIndexOnIntReturnsSelf) {
PyObjectPtr pylong(PyLong_FromLong(666));
PyObjectPtr index(PyNumber_Index(pylong));
EXPECT_EQ(index, pylong);
}
TEST_F(AbstractExtensionApiTest, PyNumberIndexOnIntSubclassReturnsSelf) {
PyRun_SimpleString(R"(
class C(int): pass
obj = C(42);
)");
PyObjectPtr obj(mainModuleGet("obj"));
PyObjectPtr index(PyNumber_Index(obj));
EXPECT_EQ(index, obj);
}
TEST_F(AbstractExtensionApiTest, PyNumberIndexCallsDunderIndex) {
PyRun_SimpleString(R"(
class IntLikeClass:
def __index__(self):
return 42;
i = IntLikeClass();
)");
PyObjectPtr i(mainModuleGet("i"));
PyObjectPtr index(PyNumber_Index(i));
ASSERT_TRUE(PyLong_CheckExact(index));
EXPECT_EQ(PyLong_AsLong(index), 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberIndexOnNullRaisesSystemError) {
ASSERT_EQ(PyNumber_Index(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberIndexOnNonIntRaisesTypeError) {
PyObjectPtr str(PyUnicode_FromString("not an int"));
ASSERT_EQ(PyNumber_Index(str), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyNumberIndexWithMistypedDunderIndexRaisesTypeError) {
PyRun_SimpleString(R"(
class IntLikeClass:
def __index__(self):
return "not an int";
i = IntLikeClass();
)");
PyObjectPtr i(mainModuleGet("i"));
ASSERT_EQ(PyNumber_Index(i), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceAddWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceAdd(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceAddWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(4));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_InPlaceAdd(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 6);
EXPECT_EQ(PyLong_AsLong(x), 4);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceAndWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceAnd(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceAndWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5)); // 0b0101
PyObjectPtr y(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_InPlaceAnd(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1); // 0b0001
EXPECT_EQ(PyLong_AsLong(x), 5);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceFloorDivideWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceFloorDivide(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceFloorDivideWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyLong_FromLong(5));
PyObjectPtr result(PyNumber_InPlaceFloorDivide(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 8);
EXPECT_EQ(PyLong_AsLong(x), 42);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceLshiftWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceLshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceLshiftIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr result(PyNumber_InPlaceLshift(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 40);
EXPECT_EQ(PyLong_AsLong(x), 5);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceMatrixMultiplyWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceMatrixMultiply(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceMatrixMultiplyCallsDunderImatmul) {
PyRun_SimpleString(R"(
class C:
def __init__(self):
self.called = False
def __imatmul__(self, other):
self.called = True
return 1
x = C()
)");
PyObjectPtr x(mainModuleGet("x"));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr called1(PyObject_GetAttrString(x, "called"));
EXPECT_EQ(called1, Py_False);
PyObjectPtr result(PyNumber_InPlaceMatrixMultiply(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
PyObjectPtr called2(PyObject_GetAttrString(x, "called"));
EXPECT_EQ(called2, Py_True);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceMultiplyWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceMultiply(x, Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceMultiplyWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(3));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_InPlaceMultiply(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 6);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceOrWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceOr(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceOrWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5)); // 0b0101
PyObjectPtr y(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_InPlaceOr(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 7); // 0b0111
EXPECT_EQ(PyLong_AsLong(x), 5);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlacePowerWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlacePower(x, y, Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlacePowerCallsDunderIpow) {
PyRun_SimpleString(R"(
class C:
def __init__(self):
self.called = False
def __ipow__(self, other):
self.called = True
return 1
x = C()
)");
PyObjectPtr x(mainModuleGet("x"));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr called1(PyObject_GetAttrString(x, "called"));
EXPECT_EQ(called1, Py_False);
PyObjectPtr result(PyNumber_InPlacePower(x, y, Py_None));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
PyObjectPtr called2(PyObject_GetAttrString(x, "called"));
EXPECT_EQ(called2, Py_True);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceRemainderWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyList_New(0));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceRemainder(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceRemainderWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyLong_FromLong(5));
PyObjectPtr result(PyNumber_InPlaceRemainder(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 2);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceRshiftWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceRshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceRshiftIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr result(PyNumber_InPlaceRshift(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 5);
EXPECT_EQ(PyLong_AsLong(x), 42);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceSubtractWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceSubtract(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceSubtractIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr result(PyNumber_InPlaceSubtract(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 2);
EXPECT_EQ(PyLong_AsLong(x), 5);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceTrueDivideWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceTrueDivide(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceTrueDivideWithFloatsReturnsFloat) {
PyObjectPtr x(PyLong_FromLong(42.0));
PyObjectPtr y(PyLong_FromLong(5));
PyObjectPtr result(PyNumber_InPlaceTrueDivide(x, y));
ASSERT_TRUE(PyFloat_CheckExact(result));
EXPECT_EQ(PyFloat_AsDouble(result), 8.4);
EXPECT_EQ(PyFloat_AsDouble(x), 42.0);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInPlaceXorWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_InPlaceXor(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInPlaceXorWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5)); // 0b0101
PyObjectPtr y(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_InPlaceXor(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 6); // 0b0110
EXPECT_EQ(PyLong_AsLong(x), 5);
}
TEST_F(AbstractExtensionApiTest, PyNumberInvertWithIntReturnsInt) {
PyObjectPtr num(PyLong_FromLong(7));
PyObjectPtr result(PyNumber_Invert(num));
EXPECT_EQ(PyLong_AsLong(result), -8);
}
TEST_F(AbstractExtensionApiTest,
PyNumberInvertWithCustomClassCallsDunderInvert) {
PyRun_SimpleString(R"(
class C:
def __invert__(self):
return "custom invert"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Invert(c));
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "custom invert"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberInvertWithNullRaisesSystemError) {
ASSERT_EQ(PyNumber_Invert(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInvertWithNonNumberRaisesTypeError) {
ASSERT_EQ(PyNumber_Positive(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberInvertPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __invert__(self):
raise UserWarning()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Invert(c));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyNumberLongWithNullRaisesSystemError) {
EXPECT_EQ(PyNumber_Long(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberLongWithIntReturnsInt) {
PyObjectPtr intobj(PyLong_FromLong(PY_SSIZE_T_MAX));
Py_ssize_t refcnt = Py_REFCNT(intobj);
PyObjectPtr result(PyNumber_Long(intobj));
ASSERT_NE(result, nullptr);
EXPECT_EQ(result, intobj);
EXPECT_EQ(Py_REFCNT(result), refcnt + 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyNumberLongDunderLongReturnsNonIntRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
def __int__(self):
return "foo"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyNumber_Long(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberLongCallsDunderTrunc) {
PyRun_SimpleString(R"(
class C:
def __trunc__(self):
return 7
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Long(c));
ASSERT_NE(result, nullptr);
EXPECT_EQ(PyLong_AsLong(result), 7);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberLongCallsDunderTruncAndDunderInt) {
PyRun_SimpleString(R"(
class D:
def __int__(self):
return 8
class C:
def __trunc__(self):
return D()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Long(c));
ASSERT_NE(result, nullptr);
EXPECT_EQ(PyLong_AsLong(result), 8);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberLongWithStringReturnsInt) {
PyObjectPtr str(PyUnicode_FromString("7"));
PyObjectPtr result(PyNumber_Long(str));
ASSERT_NE(result, nullptr);
EXPECT_EQ(PyLong_AsLong(result), 7);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyNumberLongWithUnsupportedTypeRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyNumber_Long(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberLshiftWithNonIntSelfRaisesTypeError) {
PyObjectPtr x(PyFloat_FromDouble(5.0));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_Lshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberLshiftWithNonIntOtherRaisesTypeError) {
PyObjectPtr x(PyLong_FromLong(5));
PyObjectPtr y(PyFloat_FromDouble(2.0));
ASSERT_EQ(PyNumber_Lshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberLshiftWithIntsShiftBitsLeft) {
PyObjectPtr x(PyLong_FromLong(0x13));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_Lshift(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 0x4C);
}
TEST_F(AbstractExtensionApiTest,
PyNumberMatrixMultiplyWithoutDunderMatmulRaisesTypeError) {
PyObjectPtr x(PyFloat_FromDouble(5.0));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_MatrixMultiply(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberMatrixMultiplyCallsDunderMatmul) {
PyRun_SimpleString(R"(
class C:
def __matmul__(self, other):
return other
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr result(PyNumber_MatrixMultiply(c, x));
ASSERT_TRUE(PyLong_CheckExact(result));
ASSERT_EQ(PyLong_AsLong(result), 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberMultiplyWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(5));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_Multiply(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 10);
}
TEST_F(AbstractExtensionApiTest, PyNumberMultiplyWithFloatReturnsFloat) {
PyObjectPtr x(PyFloat_FromDouble(5.0));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_Multiply(x, y));
ASSERT_TRUE(PyFloat_CheckExact(result));
ASSERT_EQ(PyFloat_AsDouble(result), 10.0);
}
TEST_F(AbstractExtensionApiTest, PyNumberMultiplyCallsDunderMul) {
PyRun_SimpleString(R"(
class C:
def __mul__(self, other):
return other
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr result(PyNumber_Multiply(c, x));
ASSERT_TRUE(PyLong_CheckExact(result));
ASSERT_EQ(PyLong_AsLong(result), 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberNegativeWithIntReturnsInt) {
PyObjectPtr num(PyLong_FromLong(-22));
PyObjectPtr result(PyNumber_Negative(num));
EXPECT_EQ(PyLong_AsLong(result), 22);
}
TEST_F(AbstractExtensionApiTest,
PyNumberNegativeWithCustomClassCallsDunderNeg) {
PyRun_SimpleString(R"(
class C:
def __neg__(self):
return "custom neg"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Negative(c));
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "custom neg"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberNegativeWithNullRaisesSystemError) {
EXPECT_EQ(PyNumber_Negative(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberNegativeWithNonNumberRaisesTypeError) {
EXPECT_EQ(PyNumber_Negative(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberNegativePropagatesException) {
PyRun_SimpleString(R"(
class C:
def __neg__(self):
raise UserWarning()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Negative(c));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyNumberOrWithNonIntRaisesTypeError) {
PyObjectPtr x(PyLong_FromLong(10));
PyObjectPtr y(PyFloat_FromDouble(2.0));
ASSERT_EQ(PyNumber_Or(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberOrWithIntsReturnsBitwiseOr) {
PyObjectPtr x(PyLong_FromLong(5)); // 0b0101
PyObjectPtr y(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_Or(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 7); // 0b0111
}
TEST_F(AbstractExtensionApiTest, PyNumberPositiveWithIntReturnsInt) {
PyObjectPtr num(PyLong_FromLong(-13));
PyObjectPtr result(PyNumber_Positive(num));
EXPECT_EQ(PyLong_AsLong(result), -13);
}
TEST_F(AbstractExtensionApiTest,
PyNumberPositiveWithCustomClassCallsDunderPos) {
PyRun_SimpleString(R"(
class C:
def __pos__(self):
return "custom pos"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Positive(c));
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "custom pos"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberPositiveWithNullRaisesSystemError) {
ASSERT_EQ(PyNumber_Positive(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyNumberPositiveWithNonNumberRaisesTypeError) {
ASSERT_EQ(PyNumber_Positive(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberPositivePropagatesException) {
PyRun_SimpleString(R"(
class C:
def __pos__(self):
raise UserWarning()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_Positive(c));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyNumberPowerWithNonNumberRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_Power(x, y, Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberPowerWithFloatReturnsFloat) {
PyObjectPtr x(PyFloat_FromDouble(2.0));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr result(PyNumber_Power(x, y, Py_None));
ASSERT_TRUE(PyFloat_CheckExact(result));
EXPECT_EQ(PyFloat_AsDouble(result), 8.0);
}
TEST_F(AbstractExtensionApiTest, PyNumberRemainderWithNonIntRaisesTypeError) {
PyObjectPtr x(PyLong_FromLong(10));
ASSERT_EQ(PyNumber_Remainder(x, Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberRemainderWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(10));
PyObjectPtr y(PyLong_FromLong(3));
PyObjectPtr result(PyNumber_Remainder(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
}
TEST_F(AbstractExtensionApiTest, PyNumberRshiftWithNonIntSelfRaisesTypeError) {
PyObjectPtr x(PyFloat_FromDouble(5.0));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_Rshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberRshiftWithNonIntOtherRaisesTypeError) {
PyObjectPtr x(PyLong_FromLong(5));
PyObjectPtr y(PyFloat_FromDouble(2.0));
ASSERT_EQ(PyNumber_Rshift(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberRshiftWithIntsShiftBitsRight) {
PyObjectPtr x(PyLong_FromLong(0x4C));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_Rshift(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 0x13);
}
TEST_F(AbstractExtensionApiTest,
PyNumberSubtractWithoutDunderSubtractRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_Subtract(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberSubtractCallsDunderSub) {
PyRun_SimpleString(R"(
class C:
def __sub__(self, other):
return other
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr result(PyNumber_Subtract(c, x));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberSubtractWithFloatReturnsFloat) {
PyObjectPtr x(PyLong_FromLong(10));
PyObjectPtr y(PyFloat_FromDouble(2.0));
PyObjectPtr result(PyNumber_Subtract(x, y));
ASSERT_TRUE(PyFloat_CheckExact(result));
EXPECT_EQ(PyFloat_AsDouble(result), 8.0);
PyObjectPtr result2(PyNumber_Subtract(y, x));
ASSERT_TRUE(PyFloat_CheckExact(result2));
EXPECT_EQ(PyFloat_AsDouble(result2), -8.0);
}
TEST_F(AbstractExtensionApiTest, PyNumberSubtractWithIntsReturnsInt) {
PyObjectPtr x(PyLong_FromLong(10));
PyObjectPtr y(PyLong_FromLong(2));
PyObjectPtr result(PyNumber_Subtract(x, y));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 8);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseWithBinaryFormatsAsBinary) {
PyObjectPtr x(PyLong_FromLong(10)); // 0b1010
PyObjectPtr result(PyNumber_ToBase(x, 2));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "0b1010"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseWithOctalFormatsAsOctal) {
PyObjectPtr x(PyLong_FromLong(520)); // 0o1010
PyObjectPtr result(PyNumber_ToBase(x, 8));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "0o1010"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseWithDecimalFormatsAsDecimal) {
PyObjectPtr x(PyLong_FromLong(12345));
PyObjectPtr result(PyNumber_ToBase(x, 10));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "12345"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseWithHexFormatsAsHex) {
PyObjectPtr x(PyLong_FromLong(0xdeadbeef));
PyObjectPtr result(PyNumber_ToBase(x, 16));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "0xdeadbeef"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseSupportsIndex) {
PyRun_SimpleString(R"(
class C:
def __index__(self):
return 42
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_ToBase(c, 8));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "0o52"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBasePropagatesIndexException) {
PyRun_SimpleString(R"(
class C:
def __index__(self):
raise ValueError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_ToBase(c, 8));
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
EXPECT_EQ(result, nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseSupportsIntSubclass) {
PyRun_SimpleString(R"(
class C(int):
pass
c = C(33)
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyNumber_ToBase(c, 16));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyUnicode_CompareWithASCIIString(result, "0x21"), 0);
}
TEST_F(AbstractExtensionApiTest, PyNumberToBaseWithInvalidBaseRaises) {
PyObjectPtr x(PyLong_FromLong(0xdeadbeef));
PyObjectPtr result(PyNumber_ToBase(x, 15));
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
EXPECT_EQ(result, nullptr);
}
TEST_F(AbstractExtensionApiTest, PyNumberTrueDivideWithNonIntRaisesTypeError) {
PyObjectPtr x(PyUnicode_FromString("foo"));
PyObjectPtr y(PyLong_FromLong(2));
ASSERT_EQ(PyNumber_TrueDivide(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberTrueDivideCallsDunderTruediv) {
PyRun_SimpleString(R"(
class C:
def __truediv__(self, other):
return other
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr result(PyNumber_TrueDivide(c, x));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 42);
}
TEST_F(AbstractExtensionApiTest, PyNumberTrueDivideWithIntsReturnsFloat) {
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyLong_FromLong(5));
PyObjectPtr result(PyNumber_TrueDivide(x, y));
ASSERT_TRUE(PyFloat_CheckExact(result));
EXPECT_EQ(PyFloat_AsDouble(result), 8.4);
}
TEST_F(AbstractExtensionApiTest, PyNumberTrueDivideWithFloatReturnsFloat) {
PyObjectPtr a(PyFloat_FromDouble(42.0));
PyObjectPtr b(PyLong_FromLong(5));
PyObjectPtr result1(PyNumber_TrueDivide(a, b));
ASSERT_TRUE(PyFloat_CheckExact(result1));
EXPECT_EQ(PyFloat_AsDouble(result1), 8.4);
PyObjectPtr x(PyLong_FromLong(42));
PyObjectPtr y(PyFloat_FromDouble(5.0));
PyObjectPtr result2(PyNumber_TrueDivide(x, y));
ASSERT_TRUE(PyFloat_CheckExact(result2));
EXPECT_EQ(PyFloat_AsDouble(result2), 8.4);
}
TEST_F(AbstractExtensionApiTest, PyNumberXorWithNonIntRaisesTypeError) {
PyObjectPtr x(PyFloat_FromDouble(5.0));
PyObjectPtr y(PyLong_FromLong(3));
ASSERT_EQ(PyNumber_Xor(x, y), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyNumberXorWithIntsReturnsBitwiseOr) {
PyObjectPtr v(PyLong_FromLong(5)); // 0b0101
PyObjectPtr w(PyLong_FromLong(3)); // 0b0011
PyObjectPtr result(PyNumber_Xor(v, w));
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 6); // 0b0110
}
// Object Protocol
TEST_F(AbstractExtensionApiTest, PyObjectCallWithArgsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr tup0(PyUnicode_FromString("one"));
PyObjectPtr tup1(PyLong_FromLong(2));
PyObjectPtr tup2(PyLong_FromLong(3));
PyObjectPtr args(PyTuple_Pack(3, tup0.get(), tup1.get(), tup2.get()));
PyObjectPtr result(PyObject_Call(func, args, nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "('one', 2, 3){}"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallWithArgsAndKwargsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr tup0(PyLong_FromLong(1));
PyObjectPtr tup1(PyLong_FromLong(2));
PyObjectPtr tup2(PyUnicode_FromString("three"));
PyObjectPtr args(PyTuple_Pack(3, tup0.get(), tup1.get(), tup2.get()));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg"));
PyObjectPtr kwarg_val(PyLong_FromLong(4));
PyDict_SetItem(kwargs, kwarg_name, kwarg_val);
PyObjectPtr result(PyObject_Call(func, args, kwargs));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(1, 2, 'three'){'kwarg': 4}"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallPropagatesException) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
raise UserWarning()
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr result(PyObject_Call(func, args, nullptr));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallWithCallableOfNativeType) {
ternaryfunc meth = [](PyObject*, PyObject*, PyObject*) {
return PyUnicode_FromString("from_tp_call");
};
static const PyType_Slot slots[] = {
{Py_tp_call, reinterpret_cast<void*>(meth)},
{0, nullptr},
};
static PyType_Spec spec = {
"__main__.Bar",
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
const_cast<PyType_Slot*>(slots),
};
PyObjectPtr type(PyType_FromSpec(&spec));
moduleSet("__main__", "Bar", type);
PyRun_SimpleString(R"(
b = Bar()
)");
PyObjectPtr func(mainModuleGet("b"));
PyObjectPtr args(PyTuple_New(0));
PyObjectPtr result(PyObject_Call(func, args, nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "from_tp_call"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallFunctionCalls) {
PyRun_SimpleString(R"(
def func(*args):
return f"{args!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(
PyObject_CallFunction(func, "(iI)s#i", 3, 7, "aaaa", 3, 99));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "((3, 7), 'aaa', 99)"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallFunctionWithTypeAndTupleCalls) {
PyObjectPtr result(
PyObject_CallFunction(reinterpret_cast<PyObject*>(&PyList_Type),
"((ss#i))", "bce", "aaaa", 3, 99));
EXPECT_TRUE(PyList_CheckExact(result));
EXPECT_EQ(PyList_Size(result), 3);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "bce"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "aaa"));
EXPECT_TRUE(isLongEqualsLong(PyList_GetItem(result, 2), 99));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallFunctionWithTypeAndListCalls) {
PyObjectPtr result(
PyObject_CallFunction(reinterpret_cast<PyObject*>(&PyList_Type), "[ss#i]",
"bce", "aaaa", 3, 99));
EXPECT_TRUE(PyList_CheckExact(result));
EXPECT_EQ(PyList_Size(result), 3);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "bce"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "aaa"));
EXPECT_TRUE(isLongEqualsLong(PyList_GetItem(result, 2), 99));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCallFunctionWithNonCallableRaisesTypeError) {
PyObjectPtr result(PyObject_CallFunction(Py_None, nullptr));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallFunctionPropagatesException) {
PyRun_SimpleString(R"(
def func():
raise UserWarning()
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(PyObject_CallFunction(func, nullptr));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallFunctionSizeTCalls) {
PyRun_SimpleString(R"(
def func(*args):
return f"{args!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(
PyObject_CallFunction(func, "is#i", 7, "bbb", Py_ssize_t{2}, 14));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(7, 'bb', 14)"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodWithEmptyTuplePassesNoArgs) {
PyRun_SimpleString(R"(
class C:
def func(self, *arg):
return f"{self.__class__.__name__} {arg}"
instance = C()
)");
PyObjectPtr instance(mainModuleGet("instance"));
PyObjectPtr result(PyObject_CallMethod(instance, "func", "()"));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "C ()"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodWithIntTuplePassesTwoInts) {
PyRun_SimpleString(R"(
class C:
def func(self, *arg):
return f"{self.__class__.__name__} {arg}"
instance = C()
)");
PyObjectPtr instance(mainModuleGet("instance"));
PyObjectPtr result(PyObject_CallMethod(instance, "func", "(ii)", 5, 10));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "C (5, 10)"));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCallMethodWithTupleAndIntPassesTwoArgs) {
PyRun_SimpleString(R"(
class C:
def func(self, *arg):
return f"{self.__class__.__name__} {arg}"
instance = C()
)");
PyObjectPtr instance(mainModuleGet("instance"));
PyObjectPtr result(PyObject_CallMethod(instance, "func", "()i", 10));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "C ((), 10)"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodCalls) {
PyRun_SimpleString(R"(
class C:
x = 42
def func(self, *args):
return f"{self.x}{args!r}"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyObject_CallMethod(c, "func", "s#(i)", "ccc", 1, 7));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "42('c', (7,))"));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCallMethodWithNonExistentMemberRaisesAttributeError) {
PyObjectPtr result(PyObject_CallMethod(Py_None, "foo", nullptr));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodPropagatesException) {
PyRun_SimpleString(R"(
class C:
def func(self):
raise UserWarning()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyObject_CallMethod(c, "func", nullptr));
EXPECT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodObjArgsCalls) {
PyRun_SimpleString(R"(
class C:
x = 23
def func(self, *args):
return f"{self.x}{args!r}"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr name(PyUnicode_FromString("func"));
PyObjectPtr arg0(PyLong_FromLong(-13));
PyObjectPtr arg1(PyUnicode_FromString("zzz"));
PyObjectPtr result(
PyObject_CallMethodObjArgs(c, name, arg0.get(), arg1.get(), nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "23(-13, 'zzz')"));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCallMethodObjArgsWithNullObjectRaisesSystemError) {
PyObjectPtr name(PyUnicode_FromString("func"));
PyObjectPtr result(PyObject_CallMethodObjArgs(nullptr, name));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCallMethodObjArgsWithNullMethodNameRaisesSystemError) {
PyObjectPtr result(PyObject_CallMethodObjArgs(Py_None, nullptr));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallMethodSizeTCalls) {
PyRun_SimpleString(R"(
class C:
x = -5
def func(self, *args):
return f"{self.x}{args!r}"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(_PyObject_CallMethod_SizeT(c, "func", "is#i", 9, "ddd",
Py_ssize_t{2}, 8));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "-5(9, 'dd', 8)"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallObjectCalls) {
PyRun_SimpleString(R"(
class C:
x = 9
def __call__(self, *args):
return f"{self.x}{args!r}"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyUnicode_FromString("two"));
PyObjectPtr three(PyLong_FromLong(3));
PyObjectPtr args(PyTuple_Pack(3, one.get(), two.get(), three.get()));
PyObjectPtr result(PyObject_CallObject(c, args));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "9(1, 'two', 3)"));
}
TEST_F(AbstractExtensionApiTest, PyObjectCallObjectWithArgsNullptrCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(PyObject_CallObject(func, nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(){}"));
}
TEST_F(AbstractExtensionApiTest, PyObjCallFunctionObjArgsWithNullReturnsNull) {
testing::PyObjectPtr test(PyObject_CallFunctionObjArgs(nullptr, nullptr));
EXPECT_EQ(nullptr, test);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PyObjCallFunctionObjArgsWithNonFunctionReturnsNull) {
testing::PyObjectPtr non_func(PyTuple_New(0));
testing::PyObjectPtr test(PyObject_CallFunctionObjArgs(non_func, nullptr));
EXPECT_EQ(test, nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectGetBufferWithBytesReturnsBuffer) {
Py_buffer buffer;
PyObjectPtr bytes(PyBytes_FromStringAndSize("hello\0world", 11));
Py_ssize_t old_refcnt = Py_REFCNT(bytes);
int result = PyObject_GetBuffer(bytes, &buffer, 0);
EXPECT_EQ(Py_REFCNT(bytes), old_refcnt + 1);
ASSERT_EQ(buffer.len, 11);
EXPECT_EQ(std::memcmp(buffer.buf, "hello\0world", 11), 0);
ASSERT_EQ(result, 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(bytes), old_refcnt);
}
TEST_F(AbstractExtensionApiTest, PyObjectGetBufferWithByteArrayReturnsBuffer) {
Py_buffer buffer;
PyObjectPtr bytearray(PyByteArray_FromStringAndSize("hello\0world", 11));
Py_ssize_t old_refcnt = Py_REFCNT(bytearray);
int result = PyObject_GetBuffer(bytearray, &buffer, 0);
EXPECT_EQ(Py_REFCNT(bytearray), old_refcnt + 1);
ASSERT_EQ(buffer.len, 11);
EXPECT_EQ(std::memcmp(buffer.buf, "hello\0world", 11), 0);
ASSERT_EQ(result, 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(bytearray), old_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithBufferProtocolObjectReturnsBuffer) {
static char contents[] = "hello world";
static Py_ssize_t contents_len = std::strlen(contents);
getbufferproc getbuffer_func = [](PyObject* obj, Py_buffer* view, int flags) {
return PyBuffer_FillInfo(view, obj, strdup(contents), contents_len,
/*readonly=*/1, flags);
};
releasebufferproc releasebuffer_func = [](PyObject*, Py_buffer* view) {
std::free(view->buf);
view->obj = nullptr;
};
PyType_Slot slots[] = {
{Py_bf_getbuffer, reinterpret_cast<void*>(getbuffer_func)},
{Py_bf_releasebuffer, reinterpret_cast<void*>(releasebuffer_func)},
{0, nullptr},
};
static PyType_Spec spec;
spec = {
"foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots,
};
PyObjectPtr type(PyType_FromSpec(&spec));
PyObjectPtr instance(PyObject_CallFunction(type, nullptr));
Py_buffer buffer;
Py_ssize_t old_refcnt = Py_REFCNT(instance);
int result = PyObject_GetBuffer(instance, &buffer, 0);
EXPECT_EQ(Py_REFCNT(instance), old_refcnt + 1);
ASSERT_EQ(buffer.len, contents_len);
EXPECT_NE(buffer.buf, contents);
EXPECT_EQ(std::memcmp(buffer.buf, contents, contents_len), 0);
ASSERT_EQ(result, 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(instance), old_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithBytesMemoryViewReturnsBuffer) {
Py_buffer buffer;
PyObjectPtr bytes(PyBytes_FromStringAndSize("hello\0world", 11));
PyObjectPtr memoryview(PyMemoryView_FromObject(bytes));
Py_ssize_t old_memoryview_refcnt = Py_REFCNT(memoryview);
Py_ssize_t old_bytes_refcnt = Py_REFCNT(bytes);
ASSERT_EQ(PyObject_GetBuffer(memoryview, &buffer, 0), 0);
// Getting the underlying buffer increments references to the underlying
// buffer, not the memoryview object itself.
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt + 1);
EXPECT_EQ(Py_REFCNT(bytes), old_bytes_refcnt);
ASSERT_EQ(buffer.len, 11);
EXPECT_EQ(std::memcmp(buffer.buf, "hello\0world", 11), 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt);
EXPECT_EQ(Py_REFCNT(bytes), old_bytes_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithBytearrayMemoryViewReturnsBuffer) {
Py_buffer buffer;
PyObjectPtr bytearray(PyByteArray_FromStringAndSize("hello\0world", 11));
PyObjectPtr memoryview_unsliced(PyMemoryView_FromObject(bytearray));
PyObjectPtr memoryview(PySequence_GetSlice(memoryview_unsliced, 0, 10));
Py_ssize_t old_memoryview_refcnt = Py_REFCNT(memoryview);
Py_ssize_t old_bytearray_refcnt = Py_REFCNT(bytearray);
ASSERT_EQ(PyObject_GetBuffer(memoryview, &buffer, 0), 0);
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt + 1);
EXPECT_EQ(Py_REFCNT(bytearray), old_bytearray_refcnt);
ASSERT_EQ(buffer.len, 10);
EXPECT_EQ(std::memcmp(buffer.buf, "hello\0worl", 10), 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt);
EXPECT_EQ(Py_REFCNT(bytearray), old_bytearray_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithFromMemoryMemoryViewReturnsBuffer) {
char memory[6] = "hello";
PyObjectPtr memoryview(
PyMemoryView_FromMemory(reinterpret_cast<char*>(memory), 6, PyBUF_READ));
Py_ssize_t old_memoryview_refcnt = Py_REFCNT(memoryview);
Py_buffer buffer;
EXPECT_EQ(PyObject_GetBuffer(memoryview, &buffer, 0), 0);
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt + 1);
ASSERT_EQ(buffer.len, 6);
EXPECT_EQ(std::memcmp(buffer.buf, "hello", 6), 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(memoryview), old_memoryview_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithByteFormattedArrayReturnsBuffer) {
PyRun_SimpleString(R"(
import array
result = array.array('b', b'hello')
)");
PyObjectPtr array(mainModuleGet("result"));
Py_ssize_t old_array_refcnt = Py_REFCNT(array);
Py_buffer buffer;
EXPECT_EQ(PyObject_GetBuffer(array, &buffer, 0), 0);
EXPECT_EQ(Py_REFCNT(array), old_array_refcnt + 1);
ASSERT_EQ(buffer.len, 5);
EXPECT_EQ(std::memcmp(buffer.buf, "hello", 5), 0);
PyBuffer_Release(&buffer);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(array), old_array_refcnt);
}
TEST_F(AbstractExtensionApiTest, PyObjectGetBufferWithQuadArrayReturnsBuffer) {
PyRun_SimpleString(R"(
import array
result = array.array('Q')
result.append(0xdeadbeef12345678)
)");
PyObjectPtr array(mainModuleGet("result"));
Py_ssize_t old_array_refcnt = Py_REFCNT(array);
Py_buffer buffer;
EXPECT_EQ(PyObject_GetBuffer(array, &buffer, 0), 0);
EXPECT_EQ(Py_REFCNT(array), old_array_refcnt + 1);
char* underlying_buffer = reinterpret_cast<char*>(buffer.buf);
ASSERT_EQ(buffer.len, 8);
EXPECT_EQ(underlying_buffer[0], '\x78');
EXPECT_EQ(underlying_buffer[1], '\x56');
EXPECT_EQ(underlying_buffer[2], '\x34');
EXPECT_EQ(underlying_buffer[3], '\x12');
EXPECT_EQ(underlying_buffer[4], '\xef');
EXPECT_EQ(underlying_buffer[5], '\xbe');
EXPECT_EQ(underlying_buffer[6], '\xad');
EXPECT_EQ(underlying_buffer[7], '\xde');
PyBuffer_Release(&buffer);
EXPECT_EQ(buffer.obj, nullptr);
EXPECT_EQ(Py_REFCNT(array), old_array_refcnt);
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithNonBufferExtensionObjectRaisesTypeError) {
PyType_Slot slots[] = {
{0, nullptr},
};
static PyType_Spec spec;
spec = {
"foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots,
};
PyObjectPtr type(PyType_FromSpec(&spec));
PyObjectPtr instance(PyObject_CallFunction(type, nullptr));
Py_buffer buffer;
EXPECT_EQ(PyObject_GetBuffer(instance, &buffer, 0), -1);
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithNonBufferManagedObjectRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
instance = C()
)");
Py_buffer buffer;
PyObjectPtr instance(mainModuleGet("instance"));
EXPECT_EQ(PyObject_GetBuffer(instance, &buffer, 0), -1);
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectGetBufferWithNonBufferBuiltinTypeRaisesTypeError) {
Py_buffer buffer;
PyObjectPtr instance(PyLong_FromLong(42));
EXPECT_EQ(PyObject_GetBuffer(instance, &buffer, 0), -1);
EXPECT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, CallFunctionObjArgsWithNoArgsReturnsValue) {
PyRun_SimpleString(R"(
def func():
return 5
)");
testing::PyObjectPtr func(testing::mainModuleGet("func"));
testing::PyObjectPtr func_result(PyObject_CallFunctionObjArgs(func, nullptr));
EXPECT_EQ(PyLong_AsLong(func_result), 5);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
CallFunctionObjArgsWithCallableClassReturnsValue) {
PyRun_SimpleString(R"(
class Foo():
def __call__(self):
return 5
f = Foo()
)");
testing::PyObjectPtr f(testing::mainModuleGet("f"));
testing::PyObjectPtr f_result(PyObject_CallFunctionObjArgs(f, nullptr));
EXPECT_EQ(PyLong_AsLong(f_result), 5);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
CallFunctionObjArgsWithManyArgumentsReturnsValue) {
PyRun_SimpleString(R"(
def func(a, b, c, d, e, f):
return a + b + c + d + e + f
)");
testing::PyObjectPtr func(testing::mainModuleGet("func"));
PyObject* one = PyLong_FromLong(1);
PyObject* two = PyLong_FromLong(2);
testing::PyObjectPtr func_result(PyObject_CallFunctionObjArgs(
func, one, one, two, two, one, two, nullptr));
Py_DECREF(one);
Py_DECREF(two);
EXPECT_EQ(PyLong_AsLong(func_result), 9);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectCheckBufferWithBytesReturnsTrue) {
PyObjectPtr obj(PyBytes_FromString("foo"));
EXPECT_TRUE(PyObject_CheckBuffer(obj.get()));
}
TEST_F(AbstractExtensionApiTest, PyObjectCheckBufferWithBytearrayReturnsTrue) {
PyObjectPtr obj(PyByteArray_FromStringAndSize("foo", 3));
EXPECT_TRUE(PyObject_CheckBuffer(obj.get()));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCheckBufferWithBufferObjectReturnsTrue) {
static char contents[] = "hello world";
static Py_ssize_t contents_len = std::strlen(contents);
getbufferproc getbuffer_func = [](PyObject* obj, Py_buffer* view, int flags) {
return PyBuffer_FillInfo(view, obj, strdup(contents), contents_len,
/*readonly=*/1, flags);
};
releasebufferproc releasebuffer_func = [](PyObject*, Py_buffer* view) {
std::free(view->buf);
view->obj = nullptr;
};
PyType_Slot slots[] = {
{Py_bf_getbuffer, reinterpret_cast<void*>(getbuffer_func)},
{Py_bf_releasebuffer, reinterpret_cast<void*>(releasebuffer_func)},
{0, nullptr},
};
static PyType_Spec spec;
spec = {
"foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots,
};
PyObjectPtr type(PyType_FromSpec(&spec));
PyObjectPtr obj(PyObject_CallFunction(type, nullptr));
EXPECT_TRUE(PyObject_CheckBuffer(obj.get()));
}
TEST_F(AbstractExtensionApiTest,
PyObjectCheckBufferWithNonByteslikeReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(2));
EXPECT_FALSE(PyObject_CheckBuffer(obj.get()));
}
TEST_F(AbstractExtensionApiTest,
PyObjectFastCallDictWithPositionalsAndKeywordArgsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObject* args[] = {
PyLong_FromLong(3),
PyUnicode_FromString("lll"),
PyLong_FromLong(2),
};
size_t n_args = Py_ARRAY_LENGTH(args);
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg"));
PyObjectPtr kwarg_value(PyLong_FromLong(7));
PyDict_SetItem(kwargs, kwarg_name, kwarg_value);
PyObjectPtr result(_PyObject_FastCallDict(func, args, n_args, kwargs));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(3, 'lll', 2){'kwarg': 7}"));
for (size_t i = 0; i < n_args; i++) {
Py_DECREF(args[i]);
}
}
TEST_F(AbstractExtensionApiTest, PyObjectFastCallDictWithNoArgsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr result(_PyObject_FastCallDict(func, nullptr, 0, nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(){}"));
}
TEST_F(AbstractExtensionApiTest, PyObjectFastCallDictWithoutKeywordArgsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObject* args[] = {
PyLong_FromLong(7),
PyUnicode_FromString("xxx"),
PyLong_FromLong(16),
};
size_t n_args = Py_ARRAY_LENGTH(args);
PyObjectPtr result(_PyObject_FastCallDict(func, args, n_args, nullptr));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(7, 'xxx', 16){}"));
for (size_t i = 0; i < n_args; i++) {
Py_DECREF(args[i]);
}
}
TEST_F(AbstractExtensionApiTest,
PyObjectFastCallDictWithZeroPositionalsAndKeywordArgsCalls) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
return f"{args!r}{kwargs!r}"
)");
PyObjectPtr func(mainModuleGet("func"));
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg"));
PyObjectPtr kwarg_value(PyLong_FromLong(2));
PyDict_SetItem(kwargs, kwarg_name, kwarg_value);
PyObjectPtr result(_PyObject_FastCallDict(func, nullptr, 0, kwargs));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "(){'kwarg': 2}"));
}
TEST_F(AbstractExtensionApiTest,
PyObjectFastCallDictWithPositionalsAndKeywordArgsPropagatesException) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
raise UserWarning()
)");
PyObjectPtr func(mainModuleGet("func"));
PyObject* args[] = {
PyLong_FromLong(8),
};
size_t n_args = Py_ARRAY_LENGTH(args);
PyObjectPtr kwargs(PyDict_New());
PyObjectPtr kwarg_name(PyUnicode_FromString("kwarg"));
PyObjectPtr kwarg_value(PyLong_FromLong(7));
PyDict_SetItem(kwargs, kwarg_name, kwarg_value);
PyObjectPtr result(_PyObject_FastCallDict(func, args, n_args, kwargs));
for (size_t i = 0; i < n_args; i++) {
Py_DECREF(args[i]);
}
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest,
PyObjectFastCallDictWithoutKeywordArgsPropagatesException) {
PyRun_SimpleString(R"(
def func(*args, **kwargs):
raise UserWarning()
)");
PyObjectPtr func(mainModuleGet("func"));
PyObject* args[] = {
PyUnicode_FromString(""),
};
size_t n_args = Py_ARRAY_LENGTH(args);
PyObjectPtr result(_PyObject_FastCallDict(func, args, n_args, nullptr));
for (size_t i = 0; i < n_args; i++) {
Py_DECREF(args[i]);
}
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_UserWarning));
}
TEST_F(AbstractExtensionApiTest, GetIterWithNoDunderIterRaises) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyObject_GetIter(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, GetIterWithNonCallableDunderIterRaises) {
PyRun_SimpleString(R"(
class C:
__iter__ = 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyObject_GetIter(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, GetIterWithDunderIterReturningNonIterRaises) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
return 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyObject_GetIter(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, GetIterPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
raise ValueError("hi")
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyObject_GetIter(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest, PyObjectIsInstanceWithNonTypeRaisesTypeError) {
PyObjectPtr obj(PyLong_FromLong(1));
PyObjectPtr cls(PyList_New(0));
EXPECT_EQ(PyObject_IsInstance(obj, cls), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectIsInstanceWithTypeReturnsTrue) {
PyObjectPtr obj(PyList_New(0));
PyObjectPtr cls(PyObject_Type(obj));
EXPECT_EQ(PyObject_IsInstance(obj, cls), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsInstanceWithSupertypeReturnsTrue) {
PyObjectPtr obj(PyLong_FromLong(0));
PyObjectPtr cls(PyObject_Type(obj));
EXPECT_EQ(PyObject_IsInstance(Py_True, cls), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsInstanceWithSubtypeReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(0));
PyObjectPtr cls(PyObject_Type(Py_True));
EXPECT_EQ(PyObject_IsInstance(obj, cls), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsInstanceWithTupleChecksTypes) {
PyObjectPtr obj1(PyList_New(0));
PyObjectPtr obj2(PyLong_FromLong(10));
PyObjectPtr cls(PyTuple_New(3));
PyTuple_SetItem(cls, 0, PyObject_Type(obj1));
PyTuple_SetItem(cls, 1, PyObject_Type(obj2));
PyTuple_SetItem(cls, 2, PySet_New(nullptr));
EXPECT_EQ(PyObject_IsInstance(Py_True, cls), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsSubclassWithNonTypeRaisesTypeError) {
PyObjectPtr obj(PyLong_FromLong(2));
PyObjectPtr subclass(PyObject_Type(obj));
PyObjectPtr superclass(PyList_New(0));
EXPECT_EQ(PyObject_IsSubclass(subclass, superclass), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectIsSubclassWithSameTypesReturnsTrue) {
PyObjectPtr obj1(PyLong_FromLong(2));
PyObjectPtr obj2(PyLong_FromLong(10));
PyObjectPtr subclass(PyObject_Type(obj1));
PyObjectPtr superclass(PyObject_Type(obj2));
EXPECT_EQ(PyObject_IsSubclass(subclass, superclass), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsSubclassWithSubtypeReturnsTrue) {
PyObjectPtr obj(PyLong_FromLong(10));
PyObjectPtr subclass(PyObject_Type(Py_True));
PyObjectPtr superclass(PyObject_Type(obj));
EXPECT_EQ(PyObject_IsSubclass(subclass, superclass), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsSubclassWithSupertypeReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(10));
PyObjectPtr subclass(PyObject_Type(obj));
PyObjectPtr superclass(PyObject_Type(Py_True));
EXPECT_EQ(PyObject_IsSubclass(subclass, superclass), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectIsSubclassWithTupleChecksTypes) {
PyObjectPtr obj1(PyList_New(0));
PyObjectPtr obj2(PyLong_FromLong(10));
PyObjectPtr subclass(PyObject_Type(Py_True));
PyObjectPtr superclass(PyTuple_New(3));
PyTuple_SetItem(superclass, 0, PyObject_Type(obj1));
PyTuple_SetItem(superclass, 1, PyObject_Type(obj2));
PyTuple_SetItem(superclass, 2, PySet_New(nullptr));
EXPECT_EQ(PyObject_IsSubclass(subclass, superclass), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthOnNullRaisesSystemError) {
EXPECT_EQ(PyObject_Length(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthWithoutDunderLenRaisesTypeError) {
PyObjectPtr num(PyLong_FromLong(3));
ASSERT_EQ(PyObject_Length(num), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthReturnsValueOfDunderLength) {
PyRun_SimpleString(R"(
class Bar:
def __len__(self): return 1
def __length_hint__(self): return 500
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthRaisingNonTypeErrorRaisesError) {
PyRun_SimpleString(R"(
class Bar:
def __len__(self): raise ValueError
def __length_hint__(self): return 500
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthRaisingTypeErrorReturnsDunderLengthHintValue) {
PyRun_SimpleString(R"(
class Bar:
def __len__(self): raise TypeError
def __length_hint__(self): return 500
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), 500);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithoutDunderLengthAndDunderLengthHintReturnsDefaultValue) {
PyRun_SimpleString(R"(
class Bar: pass
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), 234);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithNotImplementedDunderLengthHintReturnsDefaultValue) {
PyRun_SimpleString(R"(
class Bar:
def __length_hint__(self): return NotImplemented
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), 234);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthHintRaisingExceptionReturnsNegativeValue) {
PyRun_SimpleString(R"(
class Bar:
def __length_hint__(self): raise ValueError
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthHintReturningNonIntRaisesTypeError) {
PyRun_SimpleString(R"(
class Bar:
def __length_hint__(self): return "not int"
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthHintReturningLargeIntNotFitInWordRaisesOverflowError) {
PyRun_SimpleString(R"(
class Bar:
def __length_hint__(self): return 13843149871348971349871398471389473
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_OverflowError));
}
TEST_F(
AbstractExtensionApiTest,
PyObjectLengthHintWithDunderLengthHintReturningNegativeNumberRaisesValueError) {
PyRun_SimpleString(R"(
class Bar:
def __length_hint__(self): return -1
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_LengthHint(obj, 234), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithNonIntLenRaisesTypeError) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return "foo"
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithoutIndexRaisesTypeError) {
PyRun_SimpleString(R"(
class Foo: pass
class Bar:
def __len__(self): return Foo()
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithNonIntIndexRaisesTypeError) {
PyRun_SimpleString(R"(
class Foo:
def __index__(self): return None
class Bar:
def __len__(self): return Foo()
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthWithIntSubclassLargeRaisesOverflowError) {
PyRun_SimpleString(R"(
class Foo(int): pass
class Bar:
def __len__(self): return Foo(2**63)
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_OverflowError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithIntSubclassReturnsValue) {
PyRun_SimpleString(R"(
class Foo(int): pass
class Bar:
def __len__(self): return Foo(5)
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_Length(obj), 5);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithIndexReturnsValue) {
PyRun_SimpleString(R"(
class Foo:
def __index__(self): return 1
class Bar:
def __len__(self): return Foo()
obj = Bar()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PyObject_Length(obj), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthWithNegativeLenRaisesValueError) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return -5
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest,
PyObjectLengthWithOverflowRaisesOverflowError) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return 0x8000000000000000
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_OverflowError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithUnderflowRaisesValueError) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return -0x8000000000000001
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
ASSERT_EQ(PyObject_Length(obj), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithEmptyDictReturnsZero) {
PyObjectPtr dict(PyDict_New());
EXPECT_EQ(PyObject_Length(dict), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithEmptyListReturnsZero) {
PyObjectPtr list(PyList_New(0));
EXPECT_EQ(PyObject_Length(list), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithEmptyStringReturnsZero) {
PyObjectPtr str(PyUnicode_FromString(""));
EXPECT_EQ(PyObject_Length(str), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithNonEmptyDictReturnsValue) {
PyObjectPtr dict(PyDict_New());
{
PyObjectPtr value(PyLong_FromLong(3));
PyObjectPtr key1(PyLong_FromLong(1));
PyDict_SetItem(dict, key1, value);
PyObjectPtr key2(PyLong_FromLong(2));
PyDict_SetItem(dict, key2, value);
}
EXPECT_EQ(PyObject_Length(dict), 2);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithNonEmptyListReturnsValue) {
PyObjectPtr list(PyList_New(3));
EXPECT_EQ(PyObject_Length(list), 3);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectLengthWithNonEmptyStringReturnsValue) {
PyObjectPtr str(PyUnicode_FromString("foo"));
EXPECT_EQ(PyObject_Length(str), 3);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PyObjectSizeOnNullRaisesSystemError) {
EXPECT_EQ(PyObject_Size(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyObjectTypeOnNullRaisesSystemError) {
EXPECT_EQ(PyObject_Type(nullptr), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PyObjectTypeReturnsType) {
PyObjectPtr num(PyLong_FromLong(4));
PyObjectPtr type(PyObject_Type(num));
EXPECT_TRUE(PyType_Check(type));
}
TEST_F(AbstractExtensionApiTest, PyObjectTypeReturnsSameTypeForSmallAndLarge) {
PyObjectPtr str1(PyUnicode_FromString("short"));
PyObjectPtr str2(PyUnicode_FromString("This is a longer string."));
PyObjectPtr type1(PyObject_Type(str1));
PyObjectPtr type2(PyObject_Type(str2));
EXPECT_EQ(type1, type2);
}
#ifndef Py_SET_TYPE
#define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0)
#endif
TEST_F(AbstractExtensionApiTest, PySETTYPEWithObjectSetsType) {
PyRun_SimpleString(R"(
class C:
pass
class D:
pass
instance = C()
)");
PyObjectPtr class_c(mainModuleGet("C"));
PyObjectPtr class_d(mainModuleGet("D"));
PyObjectPtr instance(mainModuleGet("instance"));
EXPECT_TRUE(PyObject_IsInstance(instance, class_c));
// The instance must have an owned reference to D
Py_INCREF(class_d);
Py_SET_TYPE(instance.get(), class_d.asTypeObject());
EXPECT_TRUE(PyObject_IsInstance(instance, class_d));
}
TEST_F(AbstractExtensionApiTest, PySETTYPEWithTypeObjectSetsMetaclass) {
PyRun_SimpleString(R"(
class M(type):
pass
class C(metaclass=M):
pass
class D(type):
pass
)");
PyObjectPtr class_m(mainModuleGet("M"));
PyObjectPtr class_c(mainModuleGet("C"));
PyObjectPtr class_d(mainModuleGet("D"));
EXPECT_TRUE(PyObject_IsInstance(class_c, class_m));
// The instance must have an owned reference to D
Py_INCREF(class_d);
Py_SET_TYPE(class_c.get(), class_d.asTypeObject());
EXPECT_TRUE(PyObject_IsInstance(class_c, class_d));
}
// Sequence Protocol
TEST_F(AbstractExtensionApiTest,
PySequenceBytesToCharpArrayWithNonSequenceRaisesTypeError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(_PySequence_BytesToCharpArray(obj), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceBytesToCharpArrayWithEmptyListReturnsArray) {
PyObjectPtr obj(PyList_New(0));
char* const* array = _PySequence_BytesToCharpArray(obj);
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_NE(array, nullptr);
EXPECT_EQ(array[0], nullptr);
_Py_FreeCharPArray(array);
}
TEST_F(AbstractExtensionApiTest,
PySequenceBytesToCharpArrayWithNonBytesItemRaisesTypeError) {
PyObjectPtr obj(PyTuple_New(1));
PyTuple_SetItem(obj, 0, PyByteArray_FromStringAndSize("foo", 3));
EXPECT_EQ(_PySequence_BytesToCharpArray(obj), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceBytesToCharpArrayWithBytesSequenceReturnsArray) {
PyObjectPtr obj(PyTuple_New(3));
PyTuple_SetItem(obj, 0, PyBytes_FromString("foo"));
PyTuple_SetItem(obj, 1, PyBytes_FromString("bar"));
PyTuple_SetItem(obj, 2, PyBytes_FromString("baz"));
char* const* array = _PySequence_BytesToCharpArray(obj);
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_NE(array, nullptr);
EXPECT_STREQ(array[0], "foo");
EXPECT_STREQ(array[1], "bar");
EXPECT_STREQ(array[2], "baz");
EXPECT_EQ(array[3], nullptr);
_Py_FreeCharPArray(array);
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithoutGetItemReturnsFalse) {
PyRun_SimpleString(R"(
class ClassWithoutDunderGetItem: pass
obj = ClassWithoutDunderGetItem()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_FALSE(PySequence_Check(obj));
}
TEST_F(AbstractExtensionApiTest,
PySequenceCheckWithoutGetItemOnClassReturnsFalse) {
PyRun_SimpleString(R"(
class ClassWithoutDunderGetItem: pass
obj = ClassWithoutDunderGetItem()
obj.__getitem__ = lambda self, key : 1
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_FALSE(PySequence_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithNumericReturnsFalse) {
PyObjectPtr num(PyLong_FromLong(3));
EXPECT_FALSE(PySequence_Check(num));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithSetReturnsFalse) {
PyObjectPtr set(PySet_New(nullptr));
EXPECT_FALSE(PySequence_Check(set));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithDictReturnsFalse) {
PyObjectPtr dict(PyDict_New());
EXPECT_FALSE(PySequence_Check(dict));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithDictSubclassReturnsFalse) {
PyRun_SimpleString(R"(
class Subclass(dict): pass
obj = Subclass()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_FALSE(PySequence_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithNoneReturnsFalse) {
EXPECT_FALSE(PySequence_Check(Py_None));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithGetItemMethodReturnsTrue) {
PyRun_SimpleString(R"(
class ClassWithDunderGetItemMethod:
def __getitem__(self, key):
return None
obj = ClassWithDunderGetItemMethod()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_TRUE(PySequence_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithGetItemAttrReturnsTrue) {
PyRun_SimpleString(R"(
class ClassWithDunderGetItemAttr:
__getitem__ = 42
obj = ClassWithDunderGetItemAttr()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_TRUE(PySequence_Check(obj));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithStringReturnsTrue) {
PyObjectPtr str(PyUnicode_FromString("foo"));
EXPECT_TRUE(PySequence_Check(str));
}
TEST_F(AbstractExtensionApiTest, PySequenceCheckWithListReturnsTrue) {
PyObjectPtr list(PyList_New(3));
EXPECT_TRUE(PySequence_Check(list));
}
TEST_F(AbstractExtensionApiTest, PySequenceConcatWithNullLeftRaises) {
PyObjectPtr tuple(PyTuple_New(0));
PyObjectPtr result(PySequence_Concat(nullptr, tuple));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceConcatWithNullRightRaises) {
PyObjectPtr tuple(PyTuple_New(0));
PyObjectPtr result(PySequence_Concat(tuple, nullptr));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceConcatCallsDunderAdd) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr three(PyLong_FromLong(3));
PyObjectPtr four(PyLong_FromLong(4));
PyObjectPtr left(PyTuple_Pack(2, one.get(), two.get()));
PyObjectPtr right(PyTuple_Pack(2, three.get(), four.get()));
PyObjectPtr result(PySequence_Concat(left, right));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyTuple_CheckExact(result));
ASSERT_EQ(PyTuple_Size(result), 4);
EXPECT_EQ(PyTuple_GetItem(result, 0), PyTuple_GetItem(left, 0));
EXPECT_EQ(PyTuple_GetItem(result, 1), PyTuple_GetItem(left, 1));
EXPECT_EQ(PyTuple_GetItem(result, 2), PyTuple_GetItem(right, 0));
EXPECT_EQ(PyTuple_GetItem(result, 3), PyTuple_GetItem(right, 1));
}
TEST_F(AbstractExtensionApiTest, PySequenceRepeatWithNullSeqRaises) {
PyObjectPtr result(PySequence_Repeat(nullptr, 5));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceRepeatCallsDunderMul) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr seq(PyTuple_Pack(2, one.get(), two.get()));
PyObjectPtr result(PySequence_Repeat(seq, 2));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
ASSERT_EQ(PyTuple_Size(result), 4);
EXPECT_EQ(PyTuple_GetItem(result, 0), PyTuple_GetItem(seq, 0));
EXPECT_EQ(PyTuple_GetItem(result, 1), PyTuple_GetItem(seq, 1));
EXPECT_EQ(PyTuple_GetItem(result, 2), PyTuple_GetItem(seq, 0));
EXPECT_EQ(PyTuple_GetItem(result, 3), PyTuple_GetItem(seq, 1));
}
TEST_F(AbstractExtensionApiTest, PySequenceCountWithNullSeqRaises) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PySequence_Count(nullptr, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceCountWithNullObjRaises) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr tuple(PyTuple_Pack(2, one.get(), two.get()));
EXPECT_EQ(PySequence_Count(tuple, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceCountCountsOccurrences) {
PyObjectPtr obj(PyLong_FromLong(2));
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two1(PyLong_FromLong(2));
PyObjectPtr two2(PyLong_FromLong(2));
PyObjectPtr tuple(PyTuple_Pack(3, one.get(), two1.get(), two2.get()));
EXPECT_EQ(PySequence_Count(tuple, obj), 2);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceGetItemCallsDunderGetItem) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
return 7
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_GetItem(c, 0));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(result), 7);
}
TEST_F(AbstractExtensionApiTest, PySequenceItemCallsDunderGetItem) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
return 7
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_ITEM(c, 0));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(result), 7);
}
TEST_F(AbstractExtensionApiTest, PySequenceItemDunderGetItemRaises) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
raise Exception("foo")
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_ITEM(c, 0));
ASSERT_EQ(result, nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceSetItemWithNullValCallsDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PySequence_SetItem(c, 0, nullptr), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, PySequenceSetItemCallsDunderSetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __setitem__(self, key, val):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr val(PyLong_FromLong(4));
ASSERT_EQ(PySequence_SetItem(c, 0, val), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
PySequenceGetItemWithTupleReturnsTupleElement) {
PyObjectPtr tuple(PyTuple_New(2));
ASSERT_EQ(PyTuple_SetItem(tuple, 0, PyUnicode_FromString("first")), 0);
ASSERT_EQ(PyTuple_SetItem(tuple, 1, PyUnicode_FromString("second")), 0);
PyObjectPtr result(PySequence_GetItem(tuple, 0));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "first"));
result = PySequence_GetItem(tuple, 1);
EXPECT_TRUE(isUnicodeEqualsCStr(result, "second"));
}
TEST_F(AbstractExtensionApiTest, PySequenceGetItemWithListReturnsListElement) {
PyObjectPtr list(PyList_New(2));
ASSERT_EQ(PyList_SetItem(list, 0, PyUnicode_FromString("first")), 0);
ASSERT_EQ(PyList_SetItem(list, 1, PyUnicode_FromString("second")), 0);
PyObjectPtr result(PySequence_GetItem(list, 0));
EXPECT_TRUE(isUnicodeEqualsCStr(result, "first"));
result = PySequence_GetItem(list, 1);
EXPECT_TRUE(isUnicodeEqualsCStr(result, "second"));
}
TEST_F(AbstractExtensionApiTest, PySequenceDelItemCallsDunderDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PySequence_DelItem(c, 0), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, PySequenceContainsCallsDunderContains) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
pass
def __contains__(self, key):
return True
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(3));
ASSERT_EQ(PySequence_Contains(c, key), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceContainsPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
pass
def __contains__(self, key):
raise ValueError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(3));
ASSERT_EQ(PySequence_Contains(c, key), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
}
TEST_F(AbstractExtensionApiTest, PySequenceContainsFallsBackToIterSearch) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
pass
def __iter__(self):
return [1,2,3].__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(4));
ASSERT_EQ(PySequence_Contains(c, key), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceIndexWithNullObjRaises) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr tuple(PyTuple_Pack(2, one.get(), two.get()));
EXPECT_EQ(PySequence_Index(tuple, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceIndexFindsFirstOccurrence) {
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
PyObjectPtr tuple(PyTuple_Pack(3, one.get(), two.get(), two.get()));
EXPECT_EQ(PySequence_Index(tuple, two), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceFastWithNullObjRaisesSystemError) {
EXPECT_EQ(PySequence_Fast(nullptr, "msg"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceFastWithTupleReturnsSameObject) {
PyObjectPtr tuple(PyTuple_New(3));
PyObjectPtr result(PySequence_Fast(tuple, "msg"));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(tuple, result);
}
TEST_F(AbstractExtensionApiTest, PySequenceFastWithListReturnsSameObject) {
PyObjectPtr list(PyList_New(3));
PyObjectPtr result(PySequence_Fast(list, "msg"));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(list, result);
}
TEST_F(AbstractExtensionApiTest, PySequenceFastWithNonIterableRaisesTypeError) {
ASSERT_EQ(PySequence_Fast(Py_None, "msg"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceFastGetSizeWithTupleReturnsSize) {
PyObjectPtr tuple(PyTuple_Pack(3, Py_None, Py_None, Py_None));
PyObjectPtr fast_seq(PySequence_Fast(tuple, ""));
EXPECT_EQ(PySequence_Fast_GET_SIZE(fast_seq.get()), 3);
}
TEST_F(AbstractExtensionApiTest, PySequenceFastGetSizeWithListReturnsSize) {
PyObjectPtr list(PyList_New(0));
for (int i = 0; i < 11; i++) {
PyList_Append(list, Py_None);
}
PyObjectPtr fast_seq(PySequence_Fast(list, ""));
EXPECT_EQ(PySequence_Fast_GET_SIZE(fast_seq.get()), 11);
}
TEST_F(AbstractExtensionApiTest, PySequenceFastGetItemWithTupleReturnsItem) {
PyObjectPtr number(PyLong_FromLong(42));
PyObjectPtr tuple(PyTuple_Pack(3, Py_None, Py_None, number.get()));
PyObjectPtr fast_seq(PySequence_Fast(tuple, ""));
EXPECT_TRUE(
isLongEqualsLong(PySequence_Fast_GET_ITEM(fast_seq.get(), 2), 42));
}
TEST_F(AbstractExtensionApiTest, PySequenceFastGetItemWithListReturnsItem) {
PyObjectPtr list(PyList_New(0));
PyList_Append(list, Py_None);
PyObjectPtr number(PyLong_FromLong(42));
PyList_Append(list, number);
PyList_Append(list, Py_None);
PyObjectPtr fast_seq(PySequence_Fast(list, ""));
EXPECT_TRUE(
isLongEqualsLong(PySequence_Fast_GET_ITEM(fast_seq.get(), 1), 42));
}
TEST_F(AbstractExtensionApiTest, PySequenceFastWithIterableReturnsList) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
return (1, 2, 3).__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_Fast(c, "msg"));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyList_CheckExact(result));
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceConcatWithNullLeftRaisesSystemError) {
PyObjectPtr right(PyLong_FromLong(1));
EXPECT_EQ(PySequence_InPlaceConcat(nullptr, right), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceConcatWithNullRightRaisesSystemError) {
PyObjectPtr left(PyLong_FromLong(1));
EXPECT_EQ(PySequence_InPlaceConcat(left, nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceConcatWithByteArrayLeftReturnsByteArray) {
PyObjectPtr left(PyByteArray_FromStringAndSize("foo", 3));
PyObjectPtr right(PyBytes_FromString("bar"));
PyObjectPtr result(PySequence_InPlaceConcat(left, right));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(result, left);
EXPECT_STREQ(PyByteArray_AsString(left), "foobar");
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceConcatWithoutDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C: pass
left = C()
)");
PyObjectPtr left(mainModuleGet("left"));
PyObjectPtr right(PyLong_FromLong(42));
EXPECT_EQ(PySequence_InPlaceConcat(left, right), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceInPlaceConcatCallsDunderIadd) {
PyRun_SimpleString(R"(
class C(list):
def __add__(self, other):
return 1
def __iadd__(self, other):
return 2
left = C()
right = (1, 2, 3)
)");
PyObjectPtr left(mainModuleGet("left"));
PyObjectPtr right(mainModuleGet("right"));
PyObjectPtr result(PySequence_InPlaceConcat(left, right));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 2);
}
TEST_F(AbstractExtensionApiTest, PySequenceInPlaceConcatCallsDunderAdd) {
PyRun_SimpleString(R"(
class C(tuple):
def __add__(self, other):
return 1
left = C()
right = (1, 2, 3)
)");
PyObjectPtr left(mainModuleGet("left"));
PyObjectPtr right(mainModuleGet("right"));
PyObjectPtr result(PySequence_InPlaceConcat(left, right));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceRepeatWithNullRaisesSystemError) {
EXPECT_EQ(PySequence_InPlaceRepeat(nullptr, 0), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceInPlaceRepeatWithoutDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C: pass
obj = C()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PySequence_InPlaceRepeat(obj, 42), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceInPlaceRepeatWithTupleReturnsTuple) {
PyObjectPtr obj(Py_BuildValue("(ii)", 0, 1));
ASSERT_EQ(PyTuple_Size(obj), 2);
PyObjectPtr result(PySequence_InPlaceRepeat(obj, 3));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyTuple_Size(obj), 2);
ASSERT_TRUE(PyTuple_CheckExact(result));
EXPECT_EQ(PyTuple_Size(result), 6);
}
TEST_F(AbstractExtensionApiTest, PySequenceInPlaceRepeatCallsDunderImul) {
PyRun_SimpleString(R"(
class C(list):
def __imul__(self, other):
return 1
def __mul__(self, other):
return 2
obj = C()
)");
PyObjectPtr obj(mainModuleGet("obj"));
PyObjectPtr result(PySequence_InPlaceRepeat(obj, 0));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
}
TEST_F(AbstractExtensionApiTest, PySequenceInPlaceRepeatCallsDunderMul) {
PyRun_SimpleString(R"(
class C(tuple):
def __mul__(self, other):
return 1
obj = C()
)");
PyObjectPtr obj(mainModuleGet("obj"));
PyObjectPtr result(PySequence_InPlaceRepeat(obj, 0));
EXPECT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyLong_CheckExact(result));
EXPECT_EQ(PyLong_AsLong(result), 1);
}
TEST_F(AbstractExtensionApiTest, PySequenceLengthOnNull) {
EXPECT_EQ(PySequence_Length(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceLengthWithNonSequenceReturnsValue) {
PyRun_SimpleString(R"(
class Foo:
def __len__(self):
return 1
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PySequence_Length(obj), 1);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
// PySequence_Length fails on `dict` in CPython, but succeeds on subclasses
TEST_F(AbstractExtensionApiTest,
PySequenceLengthWithEmptyDictSubclassReturnsZero) {
PyRun_SimpleString(R"(
class Foo(dict):
pass
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
EXPECT_EQ(PySequence_Length(obj), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest,
PySequenceLengthWithNonEmptyDictSubclassReturnsValue) {
PyRun_SimpleString(R"(
class Foo(dict):
pass
obj = Foo()
)");
PyObjectPtr obj(mainModuleGet("obj"));
PyObjectPtr one(PyLong_FromLong(1));
PyObjectPtr two(PyLong_FromLong(2));
ASSERT_EQ(PyDict_SetItem(obj, one, two), 0);
ASSERT_EQ(PyDict_SetItem(obj, two, one), 0);
EXPECT_EQ(PySequence_Length(obj), 2);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, PySequenceListWithNullSeqRaisesSystemError) {
ASSERT_EQ(PySequence_List(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceListWithNonIterableRaisesTypeError) {
ASSERT_EQ(PySequence_List(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceListReturnsList) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
return (1, 2, 3).__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_List(c));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyList_CheckExact(result));
EXPECT_EQ(PyList_Size(result), 3);
}
TEST_F(AbstractExtensionApiTest,
PySequenceGetSliceWithNullSeqRaisesSystemError) {
EXPECT_EQ(PySequence_GetSlice(nullptr, 1, 2), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceGetSliceWithNonIterableRaisesTypeError) {
EXPECT_EQ(PySequence_GetSlice(Py_None, 1, 2), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceGetSliceCallsDunderGetItem) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
return 7
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_GetSlice(c, 1, 2));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
ASSERT_TRUE(PyLong_Check(result));
EXPECT_EQ(PyLong_AsLong(result), 7);
}
TEST_F(AbstractExtensionApiTest,
PySequenceSetSliceWithNullSeqRaisesSystemError) {
PyObjectPtr obj(PyList_New(0));
EXPECT_EQ(PySequence_SetSlice(nullptr, 1, 2, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceSetSliceWithNonIterableRaisesTypeError) {
PyObjectPtr obj(PyList_New(0));
EXPECT_EQ(PySequence_SetSlice(Py_None, 1, 2, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceSetSliceCallsDunderSetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __setitem__(self, key, value):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyList_New(0));
ASSERT_EQ(PySequence_SetSlice(c, 1, 2, obj), 0);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
PySequenceSetSliceWithNullObjCallsDunderDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PySequence_SetSlice(c, 1, 2, nullptr), 0);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
PySequenceDelSliceWithNullSeqRaisesSystemError) {
EXPECT_EQ(PySequence_DelSlice(nullptr, 1, 2), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceDelSliceWithNonIterableRaisesTypeError) {
EXPECT_EQ(PySequence_DelSlice(Py_None, 1, 2), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceDelSliceCallsDunderDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PySequence_DelSlice(c, 1, 2), 0);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, ObjectDelItemWithNullObjRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_DelItem(nullptr, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectDelItemWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_DelItem(obj, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectDelItemCallsDunderDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyObject_DelItem(c, key), 0);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, ObjectDelItemPropagatesDelItemException) {
PyRun_SimpleString(R"(
class C:
def __delitem__(self, key):
raise TypeError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyObject_DelItem(c, key), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
ObjectDelItemStringWithNullObjRaisesSystemError) {
EXPECT_EQ(PyObject_DelItemString(nullptr, "hello"), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
ObjectDelItemStringWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_DelItemString(obj, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectDelItemStringCallsDunderDelItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __delitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyObject_DelItemString(c, "hello"), 0);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
ObjectDelItemStringPropagatesDelitemException) {
PyRun_SimpleString(R"(
class C:
def __delitem__(self, key):
raise TypeError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyObject_DelItemString(c, "hello"), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceSizeWithNullRaisesSystemError) {
EXPECT_EQ(PySequence_Size(nullptr), -1);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, PySequenceTupleWithNullSeqRaisesSystemError) {
EXPECT_EQ(PySequence_Tuple(nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
PySequenceTupleWithNonIterableRaisesTypeError) {
EXPECT_EQ(PySequence_Tuple(Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, PySequenceTupleReturnsTuple) {
PyRun_SimpleString(R"(
class C:
def __iter__(self):
return [1, 2, 3].__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PySequence_Tuple(c));
ASSERT_NE(result, nullptr);
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyTuple_CheckExact(result));
EXPECT_EQ(PyTuple_Size(result), 3);
}
TEST_F(AbstractExtensionApiTest, ObjectGetItemWithNullObjRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_GetItem(nullptr, obj), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectGetItemWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_GetItem(obj, nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
ObjectGetItemWithNoDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyObject_GetItem(c, key), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
ObjectGetItemWithUncallableDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
__getitem__ = 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyObject_GetItem(c, key), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, ObjectGetItemCallsDunderGetItem) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
return key
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
PyObjectPtr result(PyObject_GetItem(c, key));
EXPECT_EQ(result, key);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, ObjectGetItemPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyObject_GetItem(c, key), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
}
TEST_F(AbstractExtensionApiTest,
MappingGetItemStringWithNullObjRaisesSystemError) {
EXPECT_EQ(PyMapping_GetItemString(nullptr, "hello"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
MappingGetItemStringWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_GetItemString(obj, nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
MappingGetItemStringWithNoDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_GetItemString(c, "hello"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
MappingGetItemStringWithUncallableDunderGetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
__getitem__ = 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_GetItemString(c, "hello"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, MappingGetItemStringCallsDunderGetItem) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
return key
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
const char* key = "hello";
PyObjectPtr result(PyMapping_GetItemString(c, key));
EXPECT_EQ(PyErr_Occurred(), nullptr);
EXPECT_TRUE(isUnicodeEqualsCStr(result, key));
}
TEST_F(AbstractExtensionApiTest, MappingGetItemStringPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_GetItemString(c, "hello"), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyWithNullObjReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(7));
EXPECT_EQ(PyMapping_HasKey(nullptr, obj), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyWithNullKeyReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(7));
EXPECT_EQ(PyMapping_HasKey(obj, nullptr), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyCallsDunderGetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __getitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
ASSERT_EQ(PyMapping_HasKey(c, key), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
MappingHasKeyReturnsFalseWhenExceptionIsRaised) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr key(PyLong_FromLong(7));
EXPECT_EQ(PyMapping_HasKey(c, key), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyStringWithNullObjReturnsFalse) {
EXPECT_EQ(PyMapping_HasKeyString(nullptr, "hello"), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyStringWithNullKeyReturnsFalse) {
PyObjectPtr obj(PyLong_FromLong(7));
EXPECT_EQ(PyMapping_HasKeyString(obj, nullptr), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingHasKeyStringCallsDunderGetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __getitem__(self, key):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
ASSERT_EQ(PyMapping_HasKeyString(c, "hello"), 1);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest,
MappingHasKeyStringReturnsFalseWhenExceptionIsRaised) {
PyRun_SimpleString(R"(
class C:
def __getitem__(self, key):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_HasKeyString(c, "hello"), 0);
EXPECT_EQ(PyErr_Occurred(), nullptr);
}
TEST_F(AbstractExtensionApiTest, MappingKeysWithNoKeysRaisesAttributeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_Keys(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
}
TEST_F(AbstractExtensionApiTest, MappingKeysCallsReturnsListOfKeys) {
PyRun_SimpleString(R"(
class C:
def keys(self):
return ["hello", "world"]
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Keys(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingKeysCallsReturnsListOfKeysSequence) {
PyRun_SimpleString(R"(
class C:
def keys(self):
return ("hello", "world").__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Keys(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingKeysWithDictSubclassCallsKeys) {
PyRun_SimpleString(R"(
class C(dict):
def keys(self):
return ("hello", "world").__iter__()
c = C()
c["a"] = 1
c["b"] = 2
c["c"] = 3
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Keys(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingItemsWithNoItemsRaisesAttributeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_Items(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
}
TEST_F(AbstractExtensionApiTest, MappingItemsCallsReturnsListOfItems) {
PyRun_SimpleString(R"(
class C:
def items(self):
return ["hello", "world"]
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Items(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingItemsCallsReturnsListOfItemsSequence) {
PyRun_SimpleString(R"(
class C:
def items(self):
return ("hello", "world").__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Items(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingItemsWithDictSubclassCallsItems) {
PyRun_SimpleString(R"(
class C(dict):
def items(self):
return ("hello", "world").__iter__()
c = C()
c["a"] = 1
c["b"] = 2
c["c"] = 3
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Items(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest,
MappingValuesWithNoValuesRaisesAttributeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyMapping_Values(c), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
}
TEST_F(AbstractExtensionApiTest, MappingValuesCallsReturnsListOfValues) {
PyRun_SimpleString(R"(
class C:
def values(self):
return ["hello", "world"]
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Values(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest,
MappingValuesCallsReturnsListOfValuesSequence) {
PyRun_SimpleString(R"(
class C:
def values(self):
return ("hello", "world").__iter__()
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Values(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, MappingValuesWithDictSubclassCallsValues) {
PyRun_SimpleString(R"(
class C(dict):
def values(self):
return ("hello", "world").__iter__()
c = C()
c["a"] = 1
c["b"] = 2
c["c"] = 3
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr result(PyMapping_Values(c));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(PyList_Check(result));
ASSERT_EQ(PyList_Size(result), 2);
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 0), "hello"));
EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(result, 1), "world"));
}
TEST_F(AbstractExtensionApiTest, ObjectSetItemWithNullObjRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_SetItem(nullptr, obj, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectSetItemWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_SetItem(obj, nullptr, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest, ObjectSetItemWithNullValueRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_SetItem(obj, obj, nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
ObjectSetItemWithNoDunderSetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_SetItem(c, obj, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
ObjectSetItemWithUncallableDunderSetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
__setitem__ = 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyObject_SetItem(c, obj, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, ObjectSetItemCallsDunderSetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __setitem__(self, key, val):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
ASSERT_EQ(PyObject_SetItem(c, obj, obj), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, ObjectSetItemPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __setitem__(self, key, value):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(7));
EXPECT_EQ(PyObject_SetItem(c, obj, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
}
TEST_F(AbstractExtensionApiTest,
MappingSetItemStringWithNullObjRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_SetItemString(nullptr, "hello", obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
MappingSetItemStringWithNullKeyRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_SetItemString(obj, nullptr, obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
MappingSetItemStringWithNullValueRaisesSystemError) {
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_SetItemString(obj, "hello", nullptr), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
}
TEST_F(AbstractExtensionApiTest,
MappingSetItemStringWithNoDunderSetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
pass
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_SetItemString(c, "hello", obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest,
MappingSetItemStringWithUncallableDunderSetItemRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
__setitem__ = 4
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
EXPECT_EQ(PyMapping_SetItemString(c, "hello", obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, MappingSetItemStringCallsDunderSetItem) {
PyRun_SimpleString(R"(
sideeffect = 0
class C:
def __setitem__(self, key, val):
global sideeffect
sideeffect = 10
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(1));
ASSERT_EQ(PyMapping_SetItemString(c, "hello", obj), 0);
ASSERT_EQ(PyErr_Occurred(), nullptr);
PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
}
TEST_F(AbstractExtensionApiTest, MappingSetItemStringPropagatesException) {
PyRun_SimpleString(R"(
class C:
def __setitem__(self, key, value):
raise IndexError
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr obj(PyLong_FromLong(7));
EXPECT_EQ(PyMapping_SetItemString(c, "hello", obj), -1);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
}
TEST_F(AbstractExtensionApiTest,
ObjectFormatWithNonStrFormatSpecRaisesTypeErrorPyro) {
EXPECT_EQ(PyObject_Format(Py_None, Py_None), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
TEST_F(AbstractExtensionApiTest, ObjectFormatCallsDunderFormat) {
PyRun_SimpleString(R"(
last_arguments = None
class C:
def __format__(self, format_spec):
global last_arguments
last_arguments = (self, format_spec)
return "foo"
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
PyObjectPtr fmt(PyUnicode_FromString("foo"));
PyObjectPtr result(PyObject_Format(c, fmt));
ASSERT_EQ(PyErr_Occurred(), nullptr);
EXPECT_TRUE(isUnicodeEqualsCStr(result, "foo"));
PyObjectPtr last_arguments(mainModuleGet("last_arguments"));
ASSERT_TRUE(PyTuple_Check(last_arguments));
EXPECT_EQ(PyTuple_GetItem(last_arguments, 0), c);
EXPECT_EQ(PyTuple_GetItem(last_arguments, 1), fmt);
}
TEST_F(AbstractExtensionApiTest,
ObjectFormatWithDunderFormatReturningNonStrRaisesTypeError) {
PyRun_SimpleString(R"(
class C:
def __format__(self, format_spec):
return 7
c = C()
)");
PyObjectPtr c(mainModuleGet("c"));
EXPECT_EQ(PyObject_Format(c, nullptr), nullptr);
ASSERT_NE(PyErr_Occurred(), nullptr);
EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
}
} // namespace testing
} // namespace py