diff options
-rw-r--r-- | Lib/test/test_capi/test_list.py | 277 | ||||
-rw-r--r-- | Modules/_testcapi/list.c | 180 |
2 files changed, 456 insertions, 1 deletions
diff --git a/Lib/test/test_capi/test_list.py b/Lib/test/test_capi/test_list.py new file mode 100644 index 0000000..197da03 --- /dev/null +++ b/Lib/test/test_capi/test_list.py @@ -0,0 +1,277 @@ +import unittest +import sys +from test.support import import_helper +from collections import UserList +_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 ListSubclass(list): + pass + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyList_Check() + check = _testcapi.list_check + self.assertTrue(check([1, 2])) + self.assertTrue(check([])) + self.assertTrue(check(ListSubclass([1, 2]))) + self.assertFalse(check({1: 2})) + self.assertFalse(check((1, 2))) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + + def test_list_check_exact(self): + # Test PyList_CheckExact() + check = _testcapi.list_check_exact + self.assertTrue(check([1])) + self.assertTrue(check([])) + self.assertFalse(check(ListSubclass([1]))) + self.assertFalse(check(UserList([1, 2]))) + self.assertFalse(check({1: 2})) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_list_new(self): + # Test PyList_New() + list_new = _testcapi.list_new + lst = list_new(0) + self.assertEqual(lst, []) + self.assertIs(type(lst), list) + lst2 = list_new(0) + self.assertIsNot(lst2, lst) + self.assertRaises(SystemError, list_new, NULL) + self.assertRaises(SystemError, list_new, -1) + + def test_list_size(self): + # Test PyList_Size() + size = _testcapi.list_size + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size(ListSubclass([1, 2])), 2) + self.assertRaises(SystemError, size, UserList()) + self.assertRaises(SystemError, size, {}) + self.assertRaises(SystemError, size, 23) + self.assertRaises(SystemError, size, object()) + # CRASHES size(NULL) + + def test_list_get_size(self): + # Test PyList_GET_SIZE() + size = _testcapi.list_get_size + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size(ListSubclass([1, 2])), 2) + # CRASHES size(object()) + # CRASHES size(23) + # CRASHES size({}) + # CRASHES size(UserList()) + # CRASHES size(NULL) + + + def test_list_getitem(self): + # Test PyList_GetItem() + getitem = _testcapi.list_getitem + lst = [1, 2, 3] + self.assertEqual(getitem(lst, 0), 1) + self.assertEqual(getitem(lst, 2), 3) + self.assertRaises(IndexError, getitem, lst, 3) + self.assertRaises(IndexError, getitem, lst, -1) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, getitem, 42, 1) + self.assertRaises(SystemError, getitem, (1, 2, 3), 1) + self.assertRaises(SystemError, getitem, {1: 2}, 1) + + # CRASHES getitem(NULL, 1) + + def test_list_get_item(self): + # Test PyList_GET_ITEM() + get_item = _testcapi.list_get_item + lst = [1, 2, [1, 2, 3]] + self.assertEqual(get_item(lst, 0), 1) + self.assertEqual(get_item(lst, 2), [1, 2, 3]) + + # CRASHES for out of index: get_item(lst, 3) + # CRASHES for get_item(lst, PY_SSIZE_T_MIN) + # CRASHES for get_item(lst, PY_SSIZE_T_MAX) + # CRASHES get_item(21, 2) + # CRASHES get_item(NULL, 1) + + + def test_list_setitem(self): + # Test PyList_SetItem() + setitem = _testcapi.list_setitem + lst = [1, 2, 3] + setitem(lst, 0, 10) + self.assertEqual(lst, [10, 2, 3]) + setitem(lst, 2, 12) + self.assertEqual(lst, [10, 2, 12]) + self.assertRaises(IndexError, setitem, lst, 3 , 5) + self.assertRaises(IndexError, setitem, lst, -1, 5) + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 5) + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 5) + self.assertRaises(SystemError, setitem, (1, 2, 3), 1, 5) + self.assertRaises(SystemError, setitem, {1: 2}, 1, 5) + + # CRASHES setitem(NULL, 'a', 5) + + def test_list_set_item(self): + # Test PyList_SET_ITEM() + set_item = _testcapi.list_set_item + lst = [1, 2, 3] + set_item(lst, 1, 10) + set_item(lst, 2, [1, 2, 3]) + self.assertEqual(lst, [1, 10, [1, 2, 3]]) + + # CRASHES for set_item([1], -1, 5) + # CRASHES for set_item([1], PY_SSIZE_T_MIN, 5) + # CRASHES for set_item([1], PY_SSIZE_T_MAX, 5) + # CRASHES for set_item([], 0, 1) + # CRASHES for set_item(NULL, 0, 1) + + + def test_list_insert(self): + # Test PyList_Insert() + insert = _testcapi.list_insert + lst = [1, 2, 3] + insert(lst, 0, 23) + self.assertEqual(lst, [23, 1, 2, 3]) + insert(lst, -1, 22) + self.assertEqual(lst, [23, 1, 2, 22, 3]) + insert(lst, PY_SSIZE_T_MIN, 1) + self.assertEqual(lst[0], 1) + insert(lst, len(lst), 123) + self.assertEqual(lst[-1], 123) + insert(lst, len(lst)-1, 124) + self.assertEqual(lst[-2], 124) + insert(lst, PY_SSIZE_T_MAX, 223) + self.assertEqual(lst[-1], 223) + + self.assertRaises(SystemError, insert, (1, 2, 3), 1, 5) + self.assertRaises(SystemError, insert, {1: 2}, 1, 5) + + # CRASHES insert(NULL, 1, 5) + + def test_list_append(self): + # Test PyList_Append() + append = _testcapi.list_append + lst = [1, 2, 3] + append(lst, 10) + self.assertEqual(lst, [1, 2, 3, 10]) + append(lst, [4, 5]) + self.assertEqual(lst, [1, 2, 3, 10, [4, 5]]) + self.assertRaises(SystemError, append, lst, NULL) + self.assertRaises(SystemError, append, (), 0) + self.assertRaises(SystemError, append, 42, 0) + # CRASHES append(NULL, 0) + + def test_list_getslice(self): + # Test PyList_GetSlice() + getslice = _testcapi.list_getslice + lst = [1, 2, 3] + + # empty + self.assertEqual(getslice(lst, PY_SSIZE_T_MIN, 0), []) + self.assertEqual(getslice(lst, -1, 0), []) + self.assertEqual(getslice(lst, 3, PY_SSIZE_T_MAX), []) + + # slice + self.assertEqual(getslice(lst, 1, 3), [2, 3]) + + # whole + self.assertEqual(getslice(lst, 0, len(lst)), lst) + self.assertEqual(getslice(lst, 0, 100), lst) + self.assertEqual(getslice(lst, -100, 100), lst) + + self.assertRaises(SystemError, getslice, (1, 2, 3), 0, 0) + self.assertRaises(SystemError, getslice, 'abc', 0, 0) + self.assertRaises(SystemError, getslice, 42, 0, 0) + + # CRASHES getslice(NULL, 0, 0) + + def test_list_setslice(self): + # Test PyList_SetSlice() + setslice = _testcapi.list_setslice + def set_slice(lst, low, high, value): + lst = lst.copy() + self.assertEqual(setslice(lst, low, high, value), 0) + return lst + + # insert items + self.assertEqual(set_slice([], 0, 0, list("abc")), list("abc")) + self.assertEqual(set_slice([], PY_SSIZE_T_MIN, PY_SSIZE_T_MIN, list("abc")), list("abc")) + self.assertEqual(set_slice([], PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, list("abc")), list("abc")) + lst = list("abc") + self.assertEqual(set_slice(lst, 0, 0, ["X"]), list("Xabc")) + self.assertEqual(set_slice(lst, 1, 1, list("XY")), list("aXYbc")) + self.assertEqual(set_slice(lst, len(lst), len(lst), ["X"]), list("abcX")) + # self.assertEqual(set_slice(lst, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, ["X"]), list("abcX")) + + # replace items + lst = list("abc") + self.assertEqual(set_slice(lst, -100, 1, list("X")), list("Xbc")) + self.assertEqual(set_slice(lst, 1, 2, list("X")), list("aXc")) + self.assertEqual(set_slice(lst, 1, 3, list("XY")), list("aXY")) + self.assertEqual(set_slice(lst, 0, 3, list("XYZ")), list("XYZ")) + + # delete items + lst = list("abcdef") + self.assertEqual(set_slice(lst, 0, len(lst), []), []) + self.assertEqual(set_slice(lst, -100, 100, []), []) + self.assertEqual(set_slice(lst, 1, 5, []), list("af")) + self.assertEqual(set_slice(lst, 3, len(lst), []), list("abc")) + + # delete items with NULL + lst = list("abcdef") + self.assertEqual(set_slice(lst, 0, len(lst), NULL), []) + self.assertEqual(set_slice(lst, 3, len(lst), NULL), list("abc")) + + self.assertRaises(SystemError, setslice, (), 0, 0, []) + self.assertRaises(SystemError, setslice, 42, 0, 0, []) + + # CRASHES setslice(NULL, 0, 0, []) + + def test_list_sort(self): + # Test PyList_Sort() + sort = _testcapi.list_sort + lst = [4, 6, 7, 3, 1, 5, 9, 2, 0, 8] + sort(lst) + self.assertEqual(lst, list(range(10))) + + lst2 = ListSubclass([4, 6, 7, 3, 1, 5, 9, 2, 0, 8]) + sort(lst2) + self.assertEqual(lst2, list(range(10))) + + self.assertRaises(SystemError, sort, ()) + self.assertRaises(SystemError, sort, object()) + self.assertRaises(SystemError, sort, NULL) + + + def test_list_reverse(self): + # Test PyList_Reverse() + reverse = _testcapi.list_reverse + def list_reverse(lst): + self.assertEqual(reverse(lst), 0) + return lst + + self.assertEqual(list_reverse([]), []) + self.assertEqual(list_reverse([2, 5, 10]), [10, 5, 2]) + + self.assertRaises(SystemError, reverse, ()) + self.assertRaises(SystemError, reverse, object()) + self.assertRaises(SystemError, reverse, NULL) + + def test_list_astuple(self): + # Test PyList_AsTuple() + astuple = _testcapi.list_astuple + self.assertEqual(astuple([]), ()) + self.assertEqual(astuple([2, 5, 10]), (2, 5, 10)) + + self.assertRaises(SystemError, astuple, ()) + self.assertRaises(SystemError, astuple, object()) + self.assertRaises(SystemError, astuple, NULL) diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c index 9329ddc..6ba0e7a 100644 --- a/Modules/_testcapi/list.c +++ b/Modules/_testcapi/list.c @@ -1,15 +1,193 @@ #include "parts.h" #include "util.h" +static PyObject * +list_check(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyList_Check(obj)); +} + +static PyObject * +list_check_exact(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyList_CheckExact(obj)); +} + +static PyObject * +list_new(PyObject* Py_UNUSED(module), PyObject *obj) +{ + return PyList_New(PyLong_AsSsize_t(obj)); +} + +static PyObject * +list_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyList_Size(obj)); +} + +static PyObject * +list_get_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyList_GET_SIZE(obj)); +} + +static PyObject * +list_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(PyList_GetItem(obj, i)); +} + +static PyObject * +list_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(PyList_GET_ITEM(obj, i)); +} + +static PyObject * +list_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(PyList_SetItem(obj, i, Py_XNewRef(value))); + +} + +static PyObject * +list_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); + PyList_SET_ITEM(obj, i, Py_XNewRef(value)); + Py_RETURN_NONE; + +} + +static PyObject * +list_insert(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t where; + if (!PyArg_ParseTuple(args, "OnO", &obj, &where, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_Insert(obj, where, Py_XNewRef(value))); + +} + +static PyObject * +list_append(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + if (!PyArg_ParseTuple(args, "OO", &obj, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_Append(obj, value)); +} + +static PyObject * +list_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 PyList_GetSlice(obj, ilow, ihigh); + +} + +static PyObject * +list_setslice(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t ilow, ihigh; + if (!PyArg_ParseTuple(args, "OnnO", &obj, &ilow, &ihigh, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_SetSlice(obj, ilow, ihigh, value)); +} + +static PyObject * +list_sort(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyList_Sort(obj)); +} + +static PyObject * +list_reverse(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyList_Reverse(obj)); +} + +static PyObject * +list_astuple(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyList_AsTuple(obj); +} + + + static PyMethodDef test_methods[] = { + {"list_check", list_check, METH_O}, + {"list_check_exact", list_check_exact, METH_O}, + {"list_new", list_new, METH_O}, + {"list_size", list_size, METH_O}, + {"list_get_size", list_get_size, METH_O}, + {"list_getitem", list_getitem, METH_VARARGS}, + {"list_get_item", list_get_item, METH_VARARGS}, + {"list_setitem", list_setitem, METH_VARARGS}, + {"list_set_item", list_set_item, METH_VARARGS}, + {"list_insert", list_insert, METH_VARARGS}, + {"list_append", list_append, METH_VARARGS}, + {"list_getslice", list_getslice, METH_VARARGS}, + {"list_setslice", list_setslice, METH_VARARGS}, + {"list_sort", list_sort, METH_O}, + {"list_reverse", list_reverse, METH_O}, + {"list_astuple", list_astuple, METH_O}, {NULL}, }; int _PyTestCapi_Init_List(PyObject *m) { - if (PyModule_AddFunctions(m, test_methods) < 0){ + if (PyModule_AddFunctions(m, test_methods) < 0) { return -1; } |