-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
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 all 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,261 @@ | ||
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 | ||
checknull = _testcapi._check_tuple_item_is_NULL | ||
|
||
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.assertTrue(checknull(tup2, 0)) | ||
|
||
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) | ||
# CRASHES pack(2, [1]) | ||
|
||
def test_tuple_size(self): | ||
# Test PyTuple_Size() | ||
size = _testlimitedcapi.tuple_size | ||
|
||
self.assertEqual(size(()), 0) | ||
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 = ([1], [2], [3]) | ||
self.assertEqual(getitem(tup, 0), [1]) | ||
self.assertEqual(getitem(tup, 2), [3]) | ||
|
||
tup2 = TupleSubclass(([1], [2], [3])) | ||
self.assertEqual(getitem(tup2, 0), [1]) | ||
self.assertEqual(getitem(tup2, 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, [1, 2, 3], 1) | ||
self.assertRaises(SystemError, getitem, 42, 1) | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# CRASHES getitem(NULL, 0) | ||
|
||
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]) | ||
|
||
tup2 = TupleSubclass(([1], [2], [3])) | ||
self.assertEqual(get_item(tup2, 0), [1]) | ||
self.assertEqual(get_item(tup2, 2), [3]) | ||
|
||
# CRASHES get_item(NULL, 0) | ||
|
||
def test_tuple_getslice(self): | ||
# Test PyTuple_GetSlice() | ||
getslice = _testlimitedcapi.tuple_getslice | ||
|
||
# empty | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tup = ([1], [2], [3]) | ||
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ()) | ||
self.assertEqual(getslice(tup, -1, 0), ()) | ||
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ()) | ||
self.assertEqual(getslice(tup, 1, 1), ()) | ||
self.assertEqual(getslice(tup, 2, 1), ()) | ||
tup = TupleSubclass(([1], [2], [3])) | ||
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ()) | ||
self.assertEqual(getslice(tup, -1, 0), ()) | ||
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ()) | ||
self.assertEqual(getslice(tup, 1, 1), ()) | ||
self.assertEqual(getslice(tup, 2, 1), ()) | ||
|
||
# slice | ||
tup = ([1], [2], [3], [4]) | ||
self.assertEqual(getslice(tup, 1, 3), ([2], [3])) | ||
tup = TupleSubclass(([1], [2], [3], [4])) | ||
self.assertEqual(getslice(tup, 1, 3), ([2], [3])) | ||
|
||
# whole | ||
tup = ([1], [2], [3]) | ||
self.assertEqual(getslice(tup, 0, 3), tup) | ||
self.assertEqual(getslice(tup, 0, 100), tup) | ||
self.assertEqual(getslice(tup, -100, 100), tup) | ||
tup = TupleSubclass(([1], [2], [3])) | ||
self.assertEqual(getslice(tup, 0, 3), tup) | ||
self.assertEqual(getslice(tup, 0, 100), tup) | ||
self.assertEqual(getslice(tup, -100, 100), tup) | ||
|
||
self.assertRaises(SystemError, getslice, [[1], [2], [3]], 0, 0) | ||
self.assertRaises(SystemError, getslice, 42, 0, 0) | ||
|
||
# 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 | ||
checknull = _testcapi._check_tuple_item_is_NULL | ||
|
||
tup = ([1], [2]) | ||
self.assertEqual(setitem(tup, 0, []), ([], [2])) | ||
self.assertEqual(setitem(tup, 1, []), ([1], [])) | ||
|
||
tup2 = setitem(tup, 1, NULL) | ||
self.assertTrue(checknull(tup2, 1)) | ||
|
||
tup2 = TupleSubclass(([1], [2])) | ||
self.assertRaises(SystemError, setitem, tup2, 0, []) | ||
|
||
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MIN, []) | ||
self.assertRaises(IndexError, setitem, tup, -1, []) | ||
self.assertRaises(IndexError, setitem, tup, len(tup), []) | ||
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MAX, []) | ||
self.assertRaises(SystemError, setitem, [1], 0, []) | ||
self.assertRaises(SystemError, setitem, 42, 0, []) | ||
|
||
# CRASHES setitem(NULL, 0, []) | ||
|
||
def test_tuple_set_item(self): | ||
# Test PyTuple_SET_ITEM() | ||
set_item = _testcapi.tuple_set_item | ||
checknull = _testcapi._check_tuple_item_is_NULL | ||
|
||
tup = ([1], [2]) | ||
self.assertEqual(set_item(tup, 0, []), ([], [2])) | ||
self.assertEqual(set_item(tup, 1, []), ([1], [])) | ||
|
||
tup2 = set_item(tup, 1, NULL) | ||
self.assertTrue(checknull(tup2, 1)) | ||
|
||
tup2 = TupleSubclass(([1], [2])) | ||
self.assertIs(set_item(tup2, 0, []), tup2) | ||
self.assertEqual(tup2, ([], [2])) | ||
|
||
# CRASHES set_item(tup, -1, []) | ||
# CRASHES set_item(tup, len(tup), []) | ||
# CRASHES set_item([1], 0, []) | ||
# CRASHES set_item(NULL, 0, []) | ||
|
||
def test__tuple_resize(self): | ||
# Test _PyTuple_Resize() | ||
resize = _testcapi._tuple_resize | ||
checknull = _testcapi._check_tuple_item_is_NULL | ||
|
||
a = () | ||
b = resize(a, 0, False) | ||
self.assertEqual(len(a), 0) | ||
self.assertEqual(len(b), 0) | ||
b = resize(a, 2, False) | ||
self.assertEqual(len(a), 0) | ||
self.assertEqual(len(b), 2) | ||
serhiy-storchaka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertTrue(checknull(b, 0)) | ||
self.assertTrue(checknull(b, 1)) | ||
|
||
a = ([1], [2], [3]) | ||
b = resize(a, 3) | ||
self.assertEqual(b, a) | ||
b = resize(a, 2) | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertEqual(b, a[:2]) | ||
b = resize(a, 5) | ||
self.assertEqual(len(b), 5) | ||
self.assertEqual(b[:3], a) | ||
skirpichev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertTrue(checknull(b, 3)) | ||
self.assertTrue(checknull(b, 4)) | ||
|
||
a = () | ||
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX) | ||
self.assertRaises(SystemError, resize, a, -1) | ||
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN) | ||
# refcount > 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't get how you make sure that the refcount is > 1 ? Maybe add self.assertGreater(sys.getrefcount(a), 1)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One reference from the local variable and other from a function argument. Actually, it is > 1 in all other tests too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok, it makes sense. |
||
a = (1, 2, 3) | ||
self.assertRaises(SystemError, resize, a, 3, False) | ||
self.assertRaises(SystemError, resize, a, 0, False) | ||
# non-tuple | ||
self.assertRaises(SystemError, resize, [1, 2, 3], 0, False) | ||
self.assertRaises(SystemError, resize, NULL, 0, False) | ||
|
||
if __name__ == "__main__": | ||
unittest.main() |
Uh oh!
There was an error while loading. Please reload this page.