Skip to content

Commit dbc1752

Browse files
skirpichevrawwarserhiy-storchakavstinner
authored
gh-111495: Add tests for PyTuple C API (#118757)
Co-authored-by: kalyanr <kalyan.ben10@live.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 6401cdf commit dbc1752

File tree

12 files changed

+528
-2
lines changed

12 files changed

+528
-2
lines changed

Lib/test/test_capi/test_hash.py

+4
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,7 @@ def python_hash_pointer(x):
7777
# Py_HashPointer((void*)(uintptr_t)-1) doesn't return -1 but -2
7878
VOID_P_MAX = -1 & (2 ** (8 * SIZEOF_VOID_P) - 1)
7979
self.assertEqual(hash_pointer(VOID_P_MAX), -2)
80+
81+
82+
if __name__ == "__main__":
83+
unittest.main()

Lib/test/test_capi/test_list.py

+4
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,7 @@ def test_list_extend(self):
345345

346346
# CRASHES list_extend(NULL, [])
347347
# CRASHES list_extend([], NULL)
348+
349+
350+
if __name__ == "__main__":
351+
unittest.main()

Lib/test/test_capi/test_set.py

+4
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,7 @@ def test_set_next_entry(self):
265265
with self.assertRaises(SystemError):
266266
set_next(object(), 0)
267267
# CRASHES: set_next(NULL, 0)
268+
269+
270+
if __name__ == "__main__":
271+
unittest.main()

Lib/test/test_capi/test_time.py

+4
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,7 @@ def test_time(self):
7272
# Test PyTime_Time() and PyTime_TimeRaw()
7373
self.check_clock(_testcapi.PyTime_Time, time.time)
7474
self.check_clock(_testcapi.PyTime_TimeRaw, time.time)
75+
76+
77+
if __name__ == "__main__":
78+
unittest.main()

Lib/test/test_capi/test_tuple.py

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
import unittest
2+
import sys
3+
from collections import namedtuple
4+
from test.support import import_helper
5+
6+
_testcapi = import_helper.import_module('_testcapi')
7+
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
8+
9+
NULL = None
10+
PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN
11+
PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX
12+
13+
class TupleSubclass(tuple):
14+
pass
15+
16+
17+
class CAPITest(unittest.TestCase):
18+
def test_check(self):
19+
# Test PyTuple_Check()
20+
check = _testlimitedcapi.tuple_check
21+
22+
self.assertTrue(check((1, 2)))
23+
self.assertTrue(check(()))
24+
self.assertTrue(check(TupleSubclass((1, 2))))
25+
self.assertFalse(check({1: 2}))
26+
self.assertFalse(check([1, 2]))
27+
self.assertFalse(check(42))
28+
self.assertFalse(check(object()))
29+
30+
# CRASHES check(NULL)
31+
32+
def test_tuple_checkexact(self):
33+
# Test PyTuple_CheckExact()
34+
check = _testlimitedcapi.tuple_checkexact
35+
36+
self.assertTrue(check((1, 2)))
37+
self.assertTrue(check(()))
38+
self.assertFalse(check(TupleSubclass((1, 2))))
39+
self.assertFalse(check({1: 2}))
40+
self.assertFalse(check([1, 2]))
41+
self.assertFalse(check(42))
42+
self.assertFalse(check(object()))
43+
44+
# CRASHES check(NULL)
45+
46+
def test_tuple_new(self):
47+
# Test PyTuple_New()
48+
tuple_new = _testlimitedcapi.tuple_new
49+
size = _testlimitedcapi.tuple_size
50+
checknull = _testcapi._check_tuple_item_is_NULL
51+
52+
tup1 = tuple_new(0)
53+
self.assertEqual(tup1, ())
54+
self.assertEqual(size(tup1), 0)
55+
self.assertIs(type(tup1), tuple)
56+
tup2 = tuple_new(1)
57+
self.assertIs(type(tup2), tuple)
58+
self.assertEqual(size(tup2), 1)
59+
self.assertIsNot(tup2, tup1)
60+
self.assertTrue(checknull(tup2, 0))
61+
62+
self.assertRaises(SystemError, tuple_new, -1)
63+
self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN)
64+
self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX)
65+
66+
def test_tuple_pack(self):
67+
# Test PyTuple_Pack()
68+
pack = _testlimitedcapi.tuple_pack
69+
70+
self.assertEqual(pack(0), ())
71+
self.assertEqual(pack(1, [1]), ([1],))
72+
self.assertEqual(pack(2, [1], [2]), ([1], [2]))
73+
74+
self.assertRaises(SystemError, pack, PY_SSIZE_T_MIN)
75+
self.assertRaises(SystemError, pack, -1)
76+
self.assertRaises(MemoryError, pack, PY_SSIZE_T_MAX)
77+
78+
# CRASHES pack(1, NULL)
79+
# CRASHES pack(2, [1])
80+
81+
def test_tuple_size(self):
82+
# Test PyTuple_Size()
83+
size = _testlimitedcapi.tuple_size
84+
85+
self.assertEqual(size(()), 0)
86+
self.assertEqual(size((1, 2)), 2)
87+
self.assertEqual(size(TupleSubclass((1, 2))), 2)
88+
89+
self.assertRaises(SystemError, size, [])
90+
self.assertRaises(SystemError, size, 42)
91+
self.assertRaises(SystemError, size, object())
92+
93+
# CRASHES size(NULL)
94+
95+
def test_tuple_get_size(self):
96+
# Test PyTuple_GET_SIZE()
97+
size = _testcapi.tuple_get_size
98+
99+
self.assertEqual(size(()), 0)
100+
self.assertEqual(size((1, 2)), 2)
101+
self.assertEqual(size(TupleSubclass((1, 2))), 2)
102+
103+
def test_tuple_getitem(self):
104+
# Test PyTuple_GetItem()
105+
getitem = _testlimitedcapi.tuple_getitem
106+
107+
tup = ([1], [2], [3])
108+
self.assertEqual(getitem(tup, 0), [1])
109+
self.assertEqual(getitem(tup, 2), [3])
110+
111+
tup2 = TupleSubclass(([1], [2], [3]))
112+
self.assertEqual(getitem(tup2, 0), [1])
113+
self.assertEqual(getitem(tup2, 2), [3])
114+
115+
self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MIN)
116+
self.assertRaises(IndexError, getitem, tup, -1)
117+
self.assertRaises(IndexError, getitem, tup, len(tup))
118+
self.assertRaises(IndexError, getitem, tup, PY_SSIZE_T_MAX)
119+
self.assertRaises(SystemError, getitem, [1, 2, 3], 1)
120+
self.assertRaises(SystemError, getitem, 42, 1)
121+
122+
# CRASHES getitem(NULL, 0)
123+
124+
def test_tuple_get_item(self):
125+
# Test PyTuple_GET_ITEM()
126+
get_item = _testcapi.tuple_get_item
127+
128+
tup = ([1], [2], [3])
129+
self.assertEqual(get_item(tup, 0), [1])
130+
self.assertEqual(get_item(tup, 2), [3])
131+
132+
tup2 = TupleSubclass(([1], [2], [3]))
133+
self.assertEqual(get_item(tup2, 0), [1])
134+
self.assertEqual(get_item(tup2, 2), [3])
135+
136+
# CRASHES get_item(NULL, 0)
137+
138+
def test_tuple_getslice(self):
139+
# Test PyTuple_GetSlice()
140+
getslice = _testlimitedcapi.tuple_getslice
141+
142+
# empty
143+
tup = ([1], [2], [3])
144+
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ())
145+
self.assertEqual(getslice(tup, -1, 0), ())
146+
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ())
147+
self.assertEqual(getslice(tup, 1, 1), ())
148+
self.assertEqual(getslice(tup, 2, 1), ())
149+
tup = TupleSubclass(([1], [2], [3]))
150+
self.assertEqual(getslice(tup, PY_SSIZE_T_MIN, 0), ())
151+
self.assertEqual(getslice(tup, -1, 0), ())
152+
self.assertEqual(getslice(tup, 3, PY_SSIZE_T_MAX), ())
153+
self.assertEqual(getslice(tup, 1, 1), ())
154+
self.assertEqual(getslice(tup, 2, 1), ())
155+
156+
# slice
157+
tup = ([1], [2], [3], [4])
158+
self.assertEqual(getslice(tup, 1, 3), ([2], [3]))
159+
tup = TupleSubclass(([1], [2], [3], [4]))
160+
self.assertEqual(getslice(tup, 1, 3), ([2], [3]))
161+
162+
# whole
163+
tup = ([1], [2], [3])
164+
self.assertEqual(getslice(tup, 0, 3), tup)
165+
self.assertEqual(getslice(tup, 0, 100), tup)
166+
self.assertEqual(getslice(tup, -100, 100), tup)
167+
tup = TupleSubclass(([1], [2], [3]))
168+
self.assertEqual(getslice(tup, 0, 3), tup)
169+
self.assertEqual(getslice(tup, 0, 100), tup)
170+
self.assertEqual(getslice(tup, -100, 100), tup)
171+
172+
self.assertRaises(SystemError, getslice, [[1], [2], [3]], 0, 0)
173+
self.assertRaises(SystemError, getslice, 42, 0, 0)
174+
175+
# CRASHES getslice(NULL, 0, 0)
176+
177+
def test_tuple_setitem(self):
178+
# Test PyTuple_SetItem()
179+
setitem = _testlimitedcapi.tuple_setitem
180+
checknull = _testcapi._check_tuple_item_is_NULL
181+
182+
tup = ([1], [2])
183+
self.assertEqual(setitem(tup, 0, []), ([], [2]))
184+
self.assertEqual(setitem(tup, 1, []), ([1], []))
185+
186+
tup2 = setitem(tup, 1, NULL)
187+
self.assertTrue(checknull(tup2, 1))
188+
189+
tup2 = TupleSubclass(([1], [2]))
190+
self.assertRaises(SystemError, setitem, tup2, 0, [])
191+
192+
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MIN, [])
193+
self.assertRaises(IndexError, setitem, tup, -1, [])
194+
self.assertRaises(IndexError, setitem, tup, len(tup), [])
195+
self.assertRaises(IndexError, setitem, tup, PY_SSIZE_T_MAX, [])
196+
self.assertRaises(SystemError, setitem, [1], 0, [])
197+
self.assertRaises(SystemError, setitem, 42, 0, [])
198+
199+
# CRASHES setitem(NULL, 0, [])
200+
201+
def test_tuple_set_item(self):
202+
# Test PyTuple_SET_ITEM()
203+
set_item = _testcapi.tuple_set_item
204+
checknull = _testcapi._check_tuple_item_is_NULL
205+
206+
tup = ([1], [2])
207+
self.assertEqual(set_item(tup, 0, []), ([], [2]))
208+
self.assertEqual(set_item(tup, 1, []), ([1], []))
209+
210+
tup2 = set_item(tup, 1, NULL)
211+
self.assertTrue(checknull(tup2, 1))
212+
213+
tup2 = TupleSubclass(([1], [2]))
214+
self.assertIs(set_item(tup2, 0, []), tup2)
215+
self.assertEqual(tup2, ([], [2]))
216+
217+
# CRASHES set_item(tup, -1, [])
218+
# CRASHES set_item(tup, len(tup), [])
219+
# CRASHES set_item([1], 0, [])
220+
# CRASHES set_item(NULL, 0, [])
221+
222+
def test__tuple_resize(self):
223+
# Test _PyTuple_Resize()
224+
resize = _testcapi._tuple_resize
225+
checknull = _testcapi._check_tuple_item_is_NULL
226+
227+
a = ()
228+
b = resize(a, 0, False)
229+
self.assertEqual(len(a), 0)
230+
self.assertEqual(len(b), 0)
231+
b = resize(a, 2, False)
232+
self.assertEqual(len(a), 0)
233+
self.assertEqual(len(b), 2)
234+
self.assertTrue(checknull(b, 0))
235+
self.assertTrue(checknull(b, 1))
236+
237+
a = ([1], [2], [3])
238+
b = resize(a, 3)
239+
self.assertEqual(b, a)
240+
b = resize(a, 2)
241+
self.assertEqual(b, a[:2])
242+
b = resize(a, 5)
243+
self.assertEqual(len(b), 5)
244+
self.assertEqual(b[:3], a)
245+
self.assertTrue(checknull(b, 3))
246+
self.assertTrue(checknull(b, 4))
247+
248+
a = ()
249+
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
250+
self.assertRaises(SystemError, resize, a, -1)
251+
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
252+
# refcount > 1
253+
a = (1, 2, 3)
254+
self.assertRaises(SystemError, resize, a, 3, False)
255+
self.assertRaises(SystemError, resize, a, 0, False)
256+
# non-tuple
257+
self.assertRaises(SystemError, resize, [1, 2, 3], 0, False)
258+
self.assertRaises(SystemError, resize, NULL, 0, False)
259+
260+
if __name__ == "__main__":
261+
unittest.main()

Modules/Setup.stdlib.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
164164
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
165165
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c
166-
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
166+
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c
167167
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
168168
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
169169

0 commit comments

Comments
 (0)