-
-
Notifications
You must be signed in to change notification settings - Fork 33.6k
gh-111495: Add tests for PyTuple C API #118757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
0e590c4
ddf0af7
571da31
69d9ead
3260ef4
b5b4664
1d53b0f
3248144
8451a4d
b2d0eac
a977efa
95d1544
14b3594
f9554bc
e79616f
26fc5a2
5047d6d
a2ea4c4
72aa1ed
f10160c
8a6d636
266de84
190e88a
d25eae8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| import unittest | ||
| import sys | ||
| from collections import namedtuple | ||
| from test.support import import_helper | ||
|
|
||
| _testcapi = import_helper.import_module('_testcapi') | ||
| _testlimitedcapi = import_helper.import_module('_testlimitedcapi') | ||
|
|
||
| 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 = _testlimitedcapi.tuple_check | ||
|
|
||
| self.assertTrue(check((1, 2))) | ||
| self.assertTrue(check(())) | ||
| self.assertTrue(check(TupleSubclass((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_tuple_checkexact(self): | ||
| # Test PyTuple_CheckExact() | ||
| check = _testlimitedcapi.tuple_checkexact | ||
|
|
||
| self.assertTrue(check((1, 2))) | ||
| self.assertTrue(check(())) | ||
| self.assertFalse(check(TupleSubclass((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_tuple_new(self): | ||
| # Test PyTuple_New() | ||
| tuple_new = _testlimitedcapi.tuple_new | ||
| size = _testlimitedcapi.tuple_size | ||
|
|
||
| tup1 = tuple_new(0) | ||
| self.assertEqual(tup1, ()) | ||
| self.assertEqual(size(tup1), 0) | ||
| self.assertIs(type(tup1), tuple) | ||
| tup2 = tuple_new(1) | ||
| self.assertIs(type(tup2), tuple) | ||
| self.assertEqual(size(tup2), 1) | ||
| self.assertIsNot(tup2, tup1) | ||
|
|
||
| self.assertRaises(SystemError, tuple_new, -1) | ||
| self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN) | ||
| self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX) | ||
|
|
||
| def test_tuple_pack(self): | ||
| # Test PyTuple_Pack() | ||
| pack = _testlimitedcapi.tuple_pack | ||
|
|
||
| self.assertEqual(pack(0), ()) | ||
| self.assertEqual(pack(1, 1), (1,)) | ||
| self.assertEqual(pack(2, 1, 2), (1, 2)) | ||
|
|
||
| self.assertRaises(SystemError, pack, PY_SSIZE_T_MIN) | ||
| self.assertRaises(SystemError, pack, -1) | ||
| self.assertRaises(MemoryError, pack, PY_SSIZE_T_MAX) | ||
|
|
||
| # CRASHES pack(1, NULL) | ||
|
|
||
| def test_tuple_size(self): | ||
| # Test PyTuple_Size() | ||
| size = _testlimitedcapi.tuple_size | ||
|
|
||
| self.assertEqual(size((1, 2)), 2) | ||
| self.assertEqual(size(TupleSubclass((1, 2))), 2) | ||
|
|
||
| self.assertRaises(SystemError, size, []) | ||
| self.assertRaises(SystemError, size, 42) | ||
| 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) | ||
|
|
||
| def test_tuple_getitem(self): | ||
| # Test PyTuple_GetItem() | ||
| getitem = _testlimitedcapi.tuple_getitem | ||
|
|
||
| tup = TupleSubclass((1, 2, 3)) | ||
| self.assertEqual(getitem(tup, 0), 1) | ||
| self.assertEqual(getitem(tup, 2), 3) | ||
|
|
||
| tup = (1, 2, 3) | ||
| self.assertEqual(getitem(tup, 0), 1) | ||
| self.assertEqual(getitem(tup, 2), 3) | ||
|
|
||
| self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MIN) | ||
| self.assertRaises(IndexError, getitem, tup, -1) | ||
| self.assertRaises(IndexError, getitem, tup, len(tup)) | ||
| self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MAX) | ||
| self.assertRaises(SystemError, getitem, 42, 1) | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # CRASHES getitem(NULL, 1) | ||
|
|
||
| def test_tuple_get_item(self): | ||
| # Test PyTuple_GET_ITEM() | ||
| get_item = _testcapi.tuple_get_item | ||
|
|
||
| tup = TupleSubclass((1, 2, 3)) | ||
| self.assertEqual(get_item(tup, 0), 1) | ||
| self.assertEqual(get_item(tup, 2), 3) | ||
|
|
||
| tup = (1, 2, 3) | ||
| self.assertEqual(get_item(tup, 0), 1) | ||
| self.assertEqual(get_item(tup, 2), 3) | ||
|
|
||
| def test_tuple_getslice(self): | ||
| # Test PyTuple_GetSlice() | ||
| getslice = _testlimitedcapi.tuple_getslice | ||
|
|
||
| tup = (1, 2, 3) | ||
|
|
||
| # empty | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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, 3), tup) | ||
| self.assertEqual(getslice(tup, 0, 100), tup) | ||
| self.assertEqual(getslice(tup, -100, 100), tup) | ||
|
|
||
| # CRASHES getslice(NULL, 0, 0) | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def test_tuple_setitem(self): | ||
| # Test PyTuple_SetItem() | ||
| setitem = _testlimitedcapi.tuple_setitem | ||
|
|
||
| tup = (0, 0) | ||
| self.assertEqual(setitem(tup, 0, 1), (1, 0)) | ||
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| self.assertEqual(setitem(tup, 1, 1), (0, 1)) | ||
|
|
||
| self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MIN, 1) | ||
| self.assertRaises(IndexError, setitem, tup, -1, 1) | ||
| self.assertRaises(IndexError, setitem, tup, len(tup), 1) | ||
| self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MAX, 1) | ||
|
|
||
| # CRASHES setitem(NULL, 1, 5) | ||
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| def test_tuple_set_item(self): | ||
| # Test PyTuple_SET_ITEM() | ||
| set_item = _testcapi.tuple_set_item | ||
|
|
||
| tup = (0, 0) | ||
| self.assertEqual(set_item(tup, 0, 1), (1, 0)) | ||
| self.assertEqual(set_item(tup, 1, 1), (0, 1)) | ||
|
|
||
| def test_tuple_resize(self): | ||
| # Test PyTuple_Resize() | ||
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| resize = _testcapi.tuple_resize | ||
| size = _testlimitedcapi.tuple_size | ||
| tup = resize(0) | ||
| self.assertEqual(size(tup), 0) | ||
| tup = resize(2) | ||
| self.assertEqual(size(tup), 2) | ||
| self.assertRaises(MemoryError, resize, PY_SSIZE_T_MAX) | ||
| self.assertRaises(SystemError, resize, -1) | ||
| self.assertRaises(SystemError, resize, PY_SSIZE_T_MIN) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,14 +2,80 @@ | |
| #include "util.h" | ||
|
|
||
|
|
||
| static PyObject * | ||
| tuple_get_size(PyObject *Py_UNUSED(module), PyObject *obj) | ||
| { | ||
| NULLABLE(obj); | ||
| RETURN_SIZE(PyTuple_GET_SIZE(obj)); | ||
| } | ||
|
|
||
| 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_set_item(PyObject *Py_UNUSED(module), PyObject *args) | ||
| { | ||
| PyObject *obj, *value, *newtuple; | ||
| Py_ssize_t i; | ||
| if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) { | ||
| return NULL; | ||
| } | ||
| NULLABLE(obj); | ||
| NULLABLE(value); | ||
| if (obj) { | ||
| Py_ssize_t size = PyTuple_Size(obj); | ||
serhiy-storchaka marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| newtuple = PyTuple_New(size); | ||
| if (!newtuple) { | ||
| return NULL; | ||
| } | ||
| for (Py_ssize_t n = 0; n < size; n++) { | ||
| PyTuple_SetItem(newtuple, n, Py_XNewRef(PyTuple_GetItem(obj, n))); | ||
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
||
| } | ||
| else { | ||
| newtuple = obj; | ||
|
||
| } | ||
| PyTuple_SET_ITEM(newtuple, i, Py_XNewRef(value)); | ||
skirpichev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return newtuple; | ||
| } | ||
|
|
||
| static PyObject * | ||
| tuple_resize(PyObject *Py_UNUSED(module), PyObject *args) | ||
| { | ||
| Py_ssize_t newsize; | ||
| if (!PyArg_ParseTuple(args, "n", &newsize)) { | ||
| return NULL; | ||
| } | ||
| PyObject *obj = PyTuple_New(0); | ||
| int r = _PyTuple_Resize(&obj, newsize); | ||
| if (r == -1) { | ||
| return NULL; | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| return obj; | ||
| } | ||
|
|
||
|
|
||
| static PyMethodDef test_methods[] = { | ||
| {"tuple_get_size", tuple_get_size, METH_O}, | ||
| {"tuple_get_item", tuple_get_item, METH_VARARGS}, | ||
| {"tuple_set_item", tuple_set_item, METH_VARARGS}, | ||
| {"tuple_resize", tuple_resize, METH_VARARGS}, | ||
| {NULL}, | ||
| }; | ||
|
|
||
| int | ||
| _PyTestCapi_Init_Tuple(PyObject *m) | ||
| { | ||
| if (PyModule_AddFunctions(m, test_methods) < 0){ | ||
| if (PyModule_AddFunctions(m, test_methods) < 0) { | ||
| return -1; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.