8000 gh-111138: Test the public PyList C API · vstinner/cpython@89aef64 · GitHub
[go: up one dir, main page]

Skip to content

Commit 89aef64

Browse files
committed
pythongh-111138: Test the public PyList C API
Add test_capi.test_list tests.
1 parent f6a0232 commit 89aef64

File tree

7 files changed

+409
-1
lines changed

7 files changed

+409
-1
lines changed

Lib/test/test_capi/test_list.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import unittest
2+
from collections import UserList
3+
import _testcapi
4+
5+
6+
NULL = None
7+
PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN
8+
PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX
9+
10+
PyList_Check = _testcapi.list_check
11+
PyList_CheckExact = _testcapi.list_checkexact
12+
PyList_Size = _testcapi.list_size
13+
PyList_GetItem = _testcapi.list_getitem
14+
PyList_SetItem = _testcapi.list_setitem
15+
PyList_Insert = _testcapi.list_insert
16+
PyList_Append = _testcapi.list_append
17+
PyList_Sort = _testcapi.list_sort
18+
PyList_AsTuple = _testcapi.list_astuple
19+
PyList_Reverse = _testcapi.list_reverse
20+
PyList_GetSlice = _testcapi.list_getslice
21+
PyList_SetSlice = _testcapi.list_setslice
22+
23+
24+
class ListSubclass(list):
25+
pass
26+
27+
28+
class CAPITest(unittest.TestCase):
29+
30+
def test_not_list_objects(self):
31+
for obj in (
32+
123,
33+
UserList([2, 3, 5]),
34+
(2, 3, 5), # tuple
35+
object(),
36+
):
37+
with self.subTest(obj=obj):
38+
self.assertFalse(PyList_Check(obj))
39+
self.assertFalse(PyList_CheckExact(obj))
40+
with self.assertRaises(SystemError):
41+
PyList_Size(obj)
42+
with self.assertRaises(SystemError):
43+
PyList_SetItem(obj, 0, "x")
44+
with self.assertRaises(SystemError):
45+
PyList_Insert(obj, 0, "x")
46+
with self.assertRaises(SystemError):
47+
PyList_Append(obj, "x")
48+
with self.assertRaises(SystemError):
49+
PyList_Sort(obj)
50+
with self.assertRaises(SystemError):
51+
PyList_AsTuple(obj)
52+
with self.assertRaises(SystemError):
53+
PyList_Reverse(obj)
54+
with self.assertRaises(SystemError):
55+
PyList_GetSlice(obj, 0, 1)
56+
with self.assertRaises(SystemError):
57+
PyList_SetSlice(obj, 0, 1, ["x"])
58+
59+
def test_list_check(self):
60+
self.assertTrue(PyList_Check([2, 3, 5]))
61+
#self.assertFalse(PyList_Check(NULL))
62+
63+
def test_list_checkexact(self):
64+
self.assertTrue(PyList_CheckExact([2, 3, 5]))
65+
#self.assertFalse(check(NULL))
66+
67+
def test_list_new(self):
68+
expected = [None, None, None]
69+
70+
PyList_New = _testcapi.list_new
71+
lst = PyList_New(3)
72+
self.assertEqual(lst, expected)
73+
self.assertIs(type(lst), list)
74+
lst2 = PyList_New(3)
75+
self.assertIsNot(lst2, lst)
76+
77+
def test_list_size(self):
78+
self.assertEqual(PyList_Size([2, 3, 5]), 3)
79+
80+
def test_list_getitem(self):
81+
lst = list("abc")
82+
self.assertEqual(PyList_GetItem(lst, 0), "a")
83+
self.assertEqual(PyList_GetItem(lst, 1), "b")
84+
self.assertEqual(PyList_GetItem(lst, 2), "c")
85+
86+
for invalid_index in (PY_SSIZE_T_MIN, -1, 3, PY_SSIZE_T_MAX):
87+
with self.subTest(invalid_index=invalid_index):
88+
self.assertRaises(IndexError, PyList_GetItem, lst, invalid_index)
89+
90+
lst2 = ListSubclass(lst)
91+
self.assertEqual(PyList_GetItem(lst2, 1), "b")
92+
self.assertRaises(IndexError, PyList_GetItem, lst2, 3)
93+
94+
# CRASHES PyList_GetItem(NULL, 0)
95+
96+
def test_list_setitem(self):
97+
lst = list("abc")
98+
PyList_SetItem(lst, 1, "X")
99+
self.assertEqual(lst, ["a", "X", "c"])
100+
self.assertRaises(IndexError, PyList_SetItem, lst, 3, "Y")
101+
102+
lst2 = ListSubclass(list("abc"))
103+
PyList_SetItem(lst2, 1, "X")
104+
self.assertEqual(lst2, ["a", "X", "c"])
105+
106+
# CRASHES PyList_SetItem(list("abc"), 0, NULL)
107+
# CRASHES PyList_SetItem(NULL, 0, 'x')
108+
109+
def test_list_insert(self):
110+
lst = list("abc")
111+
PyList_Insert(lst, 1, "X")
112+
self.assertEqual(lst, ["a", "X", "b", "c"])
113+
PyList_Insert(lst, -1, "Y")
114+
self.assertEqual(lst, ["a", "X", "b", "Y", "c"])
115+
PyList_Insert(lst, 100, "Z")
116+
self.assertEqual(lst, ["a", "X", "b", "Y", "c", "Z"])
117+
PyList_Insert(lst, -100, "0")
118+
self.assertEqual(lst, ["0", "a", "X", "b", "Y", "c", "Z"])
119+
120+
lst2 = ListSubclass(list("abc"))
121+
PyList_Insert(lst2, 1, "X")
122+
self.assertEqual(lst2, ["a", "X", "b", "c"])
123+
124+
with self.assertRaises(SystemError):
125+
PyList_Insert(list("abc"), 0, NULL)
126+
127+
# CRASHES PyList_Insert(NULL, 0, 'x')
128+
129+
def test_list_append(self):
130+
131+
lst = []
132+
PyList_Append(lst, "a")
133+
self.assertEqual(lst, ["a"])
134+
PyList_Append(lst, "b")
135+
self.assertEqual(lst, ["a", "b"])
136+
137+
lst2 = ListSubclass()
138+
PyList_Append(lst2, "X")
139+
self.assertEqual(lst2, ["X"])
140+
141+
self.assertRaises(SystemError, PyList_Append, [], NULL)
142+
143+
# CRASHES PyList_Append(NULL, 'a')
144+
145+
def test_list_sort(self):
146+
lst = [4, 6, 7, 3, 1, 5, 9, 2, 0, 8]
147+
PyList_Sort(lst)
148+
self.assertEqual(lst, list(range(10)))
149+
150+
lst2 = ListSubclass([4, 6, 7, 3, 1, 5, 9, 2, 0, 8])
151+
PyList_Sort(lst2)
152+
self.assertEqual(lst2, list(range(10)))
153+
154+
with self.assertRaises(SystemError):
155+
PyList_Sort(NULL)
156+
157+
def test_list_astuple(self):
158+
self.assertEqual(PyList_AsTuple([]), ())
159+
self.assertEqual(PyList_AsTuple([2, 5, 10]), (2, 5, 10))
160+
161+
with self.assertRaises(SystemError):
162+
PyList_AsTuple(NULL)
163+
164+
def test_list_reverse(self):
165+
def list_reverse(lst):
166+
self.assertEqual(PyList_Reverse(lst), 0)
167+
return lst
168+
169+
self.assertEqual(list_reverse([]), [])
170+
self.assertEqual(list_reverse([2, 5, 10]), [10, 5, 2])
171+
172+
with self.assertRaises(SystemError):
173+
PyList_Reverse(NULL)
174+
175+
def test_list_getslice(self):
176+
lst = list("abcdef")
177+
self.assertEqual(PyList_GetSlice(lst, -100, 0), [])
178+
self.assertEqual(PyList_GetSlice(lst, 0, 0), [])
179+
180+
self.assertEqual(PyList_GetSlice(lst, 1, 3), list("bc"))
181+
self.assertEqual(PyList_GetSlice(lst, 0, len(lst)), lst)
182+
self.assertEqual(PyList_GetSlice(lst, 0, 100), lst)
183+
self.assertEqual(PyList_GetSlice(lst, -100, 100), lst)
184+
185+
self.assertEqual(PyList_GetSlice(lst, 100, 0), [])
186+
187+
# CRASHES PyList_GetSlice(NULL, 0, 0)
188+
189+
def test_list_setslice(self):
190+
def set_slice(lst, low, high, value):
191+
lst = lst.copy()
192+
self.assertEqual(PyList_SetSlice(lst, low, high, value), 0)
193+
return lst
194+
195+
# insert items
196+
self.assertEqual(set_slice([], 0, 0, list("abc")), list("abc"))
197+
lst = list("abc")
198+
self.assertEqual(set_slice(lst, 0, 0, ["X"]), list("Xabc"))
199+
self.assertEqual(set_slice(lst, 1, 1, list("XY")), list("aXYbc"))
200+
self.assertEqual(set_slice(lst, len(lst), len(lst), ["X"]), list("abcX"))
201+
self.assertEqual(set_slice(lst, 100, 100, ["X"]), list("abcX"))
202+
203+
# replace items
204+
lst = list("abc")
205+
self.assertEqual(set_slice(lst, -100, 1, list("X")), list("Xbc"))
206+
self.assertEqual(set_slice(lst, 1, 2, list("X")), list("aXc"))
207+
self.assertEqual(set_slice(lst, 1, 3, list("XY")), list("aXY"))
208+
self.assertEqual(set_slice(lst, 0, 3, list("XYZ")), list("XYZ"))
209+
210+
# delete items
211+
lst = list("abcdef")
212+
self.assertEqual(set_slice(lst, 0, len(lst), []), [])
213+
self.assertEqual(set_slice(lst, -100, 100, []), [])
214+
self.assertEqual(set_slice(lst, 1, 5, []), list("af"))
215+
self.assertEqual(set_slice(lst, 3, len(lst), []), list("abc"))
216+
217+
# delete items with NULL
218+
lst = list("abcdef")
219+
self.assertEqual(set_slice(lst, 0, len(lst), NULL), [])
220+
self.assertEqual(set_slice(lst, 3, len(lst), NULL), list("abc"))
221+
222+
# CRASHES PyList_SetSlice(NULL, 0, 0, ["x"])
223+
224+
225+
if __name__ == "__main__":
226+
unittest.main()

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@
159159
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
160160
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
161161
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c
162-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c
162+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/list.c _testcapi/set.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c
163163
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
164164
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
165165

0 commit comments

Comments
 (0)
0