diff --git a/Lib/test/test_capi/test_tuple.py b/Lib/test/test_capi/test_tuple.py new file mode 100644 index 00000000000000..503622d1a1cfbd --- /dev/null +++ b/Lib/test/test_capi/test_tuple.py @@ -0,0 +1,160 @@ +import unittest +import sys +from collections import namedtuple +from test.support import import_helper +_testcapi = import_helper.import_module('_testcapi') + +NULL = None +PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN +PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX + +class TupleSubclass(tuple): + pass + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyTuple_Check() + check = _testcapi.tuple_check + self.assertTrue(check((1, 2))) + self.assertTrue(check(())) + self.assertFalse(check({1: 2})) + self.assertFalse(check([1, 2])) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + + def test_tuple_checkexact(self): + # Test PyTuple_CheckExact() + check = _testcapi.tuple_checkexact + self.assertTrue(check((1, 2))) + self.assertTrue(check(())) + self.assertFalse(check(TupleSubclass((1, 2)))) + self.assertFalse(check({1: 2})) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_tuple_new(self): + # Test PyTuple_New() + tuple_new = _testcapi.tuple_new + tup = tuple_new(0) + self.assertEqual(tup, ()) + self.assertIs(type(tup), tuple) + tup2 = tuple_new(1) + self.assertIsNot(tup2, tup) + self.assertRaises(SystemError, tuple_new, NULL) + self.assertRaises(SystemError, tuple_new, -1) + + + def test_tuple_pack(self): + # Test PyTuple_Pack() + pass + + def test_tuple_size(self): + # Test PyTuple_Size() + size = _testcapi.tuple_size + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size(TupleSubclass((1, 2))), 2) + self.assertRaises(SystemError, size, {}) + self.assertRaises(SystemError, size, 23) + self.assertRaises(SystemError, size, object()) + + # CRASHES size(NULL) + + def test_tuple_get_size(self): + # Test PyTuple_GET_SIZE() + size = _testcapi.tuple_get_size + self.assertEqual(size(()), 0) + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size(TupleSubclass((1, 2))), 2) + # CRASHES size(object()) + # CRASHES size(23) + # CRASHES size({}) + # CRASHES size(UserList()) + # CRASHES size(NULL) + + + def test_tuple_getitem(self): + # Test PyTuple_GetItem() + getitem = _testcapi.tuple_getitem + tup = (1, 2, 3) + self.assertEqual(getitem(tup, 0), 1) + self.assertEqual(getitem(tup, len(tup)-1), 3) + self.assertRaises(IndexError, getitem, tup, -1) + self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MIN) + self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MAX) + self.assertRaises(IndexError, getitem, tup, len(tup)) + self.assertRaises(SystemError, getitem, 42, 1) + + # # CRASHES getitem(NULL, 1) + + def test_tuple_get_item(self): + # Test PyTuple_GET_ITEM() + get_item = _testcapi.tuple_get_item + tup = (1, 2, 3) + self.assertEqual(get_item(tup, 0), 1) + self.assertEqual(get_item(tup, 2), 3) + + # CRASHES for get_item(tup, -1) + # CRASHES for get_item(tup, PY_SSIZE_T_MIN) + # CRASHES for get_item(tup, PY_SSIZE_T_MAX) + # CRASHES for out of index: get_item(tup, 3) + # CRASHES get_item(21, 2) + # CRASHES get_item(Null,1) + + def test_tuple_getslice(self): + # Test PyTuple_GetSlice() + getslice = _testcapi.tuple_getslice + tup = (1,2,3) + + # empty + self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ()) + self.assertEqual(getslice(tup, -1, 0), ()) + self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ()) + + # slice + self.assertEqual(getslice(tup, 1, 3), (2, 3)) + + # whole + self.assertEqual(getslice(tup, 0, len(tup)), tup) + self.assertEqual(getslice(tup, 0, 100), tup) + self.assertEqual(getslice(tup, -100, 100), tup) + + self.assertRaises(TypeError, tup, 'a', '2') + + # CRASHES getslice(NULL, 0, 0) + + + def test_tuple_setitem(self): + # Test PyTuple_SetItem() + setitem = _testcapi.tuple_setitem + tup = (1, 2, 3) + self.assertRaises(SystemError, setitem, tup, 1, 0) + self.assertRaises(SystemError, setitem, {}, 0, 5) + self.assertRaises(SystemError, setitem, tup, PY_SSIZE_T_MIN, 5) + self.assertRaises(SystemError, setitem, tup, PY_SSIZE_T_MAX, 5) + self.assertRaises(SystemError, setitem, tup, -1, 5) + self.assertRaises(SystemError, setitem, tup, len(tup) , 5) + self.assertRaises(TypeError, setitem, 23, 'a', 5) + self.assertRaises(TypeError, setitem, tup, 1.5, 10) + + # CRASHES setitem(NULL, 'a', 5) + + def test_tuple_set_item(self): + # Test PyTuple_SET_ITEM() + set_item = _testcapi.tuple_set_item + tup = (1, 2, 3) + set_item(tup, 1, (1, 2)) + self.assertEqual(tup, (1, (1, 2), 3)) + + # CRASHES for set_item([1], PY_SSIZE_T_MIN, 5) + # CRASHES for set_item([1], PY_SSIZE_T_MAX, 5) + # CRASHES for set_item([1], -1, 5) + # CRASHES for set_item([], 0, 1) + # CRASHES for set_item(NULL, 0, 1) + + def test_tuple_resize(self): + # Test PyTuple_Resize() + pass diff --git a/Modules/_testcapi/tuple.c b/Modules/_testcapi/tuple.c index 95dde8c0edadbe..cbab5bb93d1fc7 100644 --- a/Modules/_testcapi/tuple.c +++ b/Modules/_testcapi/tuple.c @@ -2,7 +2,140 @@ #include "util.h" +static PyObject * +tuple_check(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyTuple_Check(obj)); +} + +static PyObject * +tuple_checkexact(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyTuple_CheckExact(obj)); +} + +static PyObject * +tuple_new(PyObject* Py_UNUSED(module), PyObject *obj) +{ + return PyTuple_New(PyLong_AsSsize_t(obj)); +} + +static PyObject * +tuple_pack(PyObject *Py_UNUSED(module), PyObject *args) +{ + Py_RETURN_NONE; +} + +static PyObject * +tuple_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyTuple_Size(obj)); +} + +static PyObject * +tuple_get_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyTuple_GET_SIZE(obj)); +} + +static PyObject * +tuple_getitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)){ + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyTuple_GetItem(obj, i)); +} + +static PyObject * +tuple_get_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)){ + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyTuple_GET_ITEM(obj, i)); +} + +static PyObject * +tuple_getslice(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t ilow, ihigh; + if ( !PyArg_ParseTuple(args, "Onn", &obj, &ilow, &ihigh)){ + return NULL; + } + NULLABLE(obj); + return PyTuple_GetSlice(obj, ilow, ihigh); + +} + +static PyObject * +tuple_setitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t i; + if ( !PyArg_ParseTuple(args, "OnO", &obj, &i, &value)){ + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyTuple_SetItem(obj, i, Py_XNewRef(value))); + +} + +static PyObject * +tuple_set_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t i; + if ( !PyArg_ParseTuple(args, "OnO", &obj, &i, &value)){ + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + PyTuple_SET_ITEM(obj, i, Py_XNewRef(value)); + Py_RETURN_NONE; + +} + +static PyObject * +tuple_resize(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t newsize; + if ( !PyArg_ParseTuple(args, "On", &obj, &newsize)){ + return NULL; + } + NULLABLE(obj); + RETURN_INT(_PyTuple_Resize(obj, newsize)); + +} + + + static PyMethodDef test_methods[] = { + {"tuple_check", tuple_check, METH_O}, + {"tuple_checkexact", tuple_checkexact, METH_O}, + {"tuple_new", tuple_new, METH_O}, + {"tuple_pack", tuple_pack, METH_VARARGS}, + {"tuple_size", tuple_size, METH_O}, + {"tuple_get_size", tuple_get_size, METH_O}, + {"tuple_getitem", tuple_getitem, METH_VARARGS}, + {"tuple_get_item", tuple_get_item, METH_VARARGS}, + {"tuple_getslice", tuple_getslice, METH_VARARGS}, + {"tuple_setitem", tuple_setitem, METH_VARARGS}, + {"tuple_set_item", tuple_set_item, METH_VARARGS}, + {"tuple_resize", tuple_resize, METH_VARARGS}, {NULL}, };