8000 [3.12] gh-110628: Add tests for PyLong C API (GH-110629) (GH-110854) · python/cpython@7c3e8e5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c3e8e5

Browse files
[3.12] gh-110628: Add tests for PyLong C API (GH-110629) (GH-110854)
(cherry picked from commit 9d40ebf)
1 parent 9a62322 commit 7c3e8e5

File tree

3 files changed

+590
-0
lines changed

3 files changed

+590
-0
lines changed

Lib/test/test_capi/test_long.py

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@
66
# Skip this test if the _testcapi module isn't available.
77
_testc 8000 api = import_helper.import_module('_testcapi')
88

9+
NULL = None
10+
11+
class IntSubclass(int):
12+
pass
13+
14+
class Index:
15+
def __init__(self, value):
16+
self.value = value
17+
18+
def __index__(self):
19+
return self.value
20+
21+
# use __index__(), not __int__()
22+
class MyIndexAndInt:
23+
def __index__(self):
24+
return 10
25+
def __int__(self):
26+
return 22
27+
928

1029
class LongTests(unittest.TestCase):
1130

@@ -34,6 +53,353 @@ def test_compact_known(self):
3453
self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize),
3554
(False, -1))
3655

56+
def test_long_check(self):
57+
# Test PyLong_Check()
58+
check = _testcapi.pylong_check
59+
self.assertTrue(check(1))
60+
self.assertTrue(check(123456789012345678901234567890))
61+
self.assertTrue(check(-1))
62+
self.assertTrue(check(True))
63+
self.assertTrue(check(IntSubclass(1)))
64+
self.assertFalse(check(1.0))
65+
self.assertFalse(check(object()))
66+
# CRASHES check(NULL)
67+
68+
def test_long_checkexact(self):
69+
# Test PyLong_CheckExact()
70+
check = _testcapi.pylong_checkexact
71+
self.assertTrue(check(1))
72+
self.assertTrue(check(123456789012345678901234567890))
73+
self.assertTrue(check(-1))
74+
self.assertFalse(check(True))
75+
self.assertFalse(check(IntSubclass(1)))
76+
self.assertFalse(check(1.0))
77+
self.assertFalse(check(object()))
78+
# CRASHES check(NULL)
79+
80+
def test_long_fromdouble(self):
81+
# Test PyLong_FromDouble()
82+
fromdouble = _testcapi.pylong_fromdouble
83+
float_max = sys.float_info.max
84+
for value in (5.0, 5.1, 5.9, -5.1, -5.9, 0.0, -0.0, float_max, -float_max):
85+
with self.subTest(value=value):
86+
self.assertEqual(fromdouble(value), int(value))
87+
self.assertRaises(OverflowError, fromdouble, float('inf'))
88+
self.assertRaises(OverflowError, fromdouble, float('-inf'))
89+
self.assertRaises(ValueError, fromdouble, float('nan'))
90+
91+
def test_long_fromvoidptr(self):
92+
# Test PyLong_FromVoidPtr()
93+
fromvoidptr = _testcapi.pylong_fromvoidptr
94+
obj = object()
95+
x = fromvoidptr(obj)
96+
y = fromvoidptr(NULL)
97+
self.assertIsInstance(x, int)
98+
self.assertGreaterEqual(x, 0)
99+
self.assertIsInstance(y, int)
100+
self.assertEqual(y, 0)
101+
self.assertNotEqual(x, y)
102+
103+
def test_long_fromstring(self):
104+
# Test PyLong_FromString()
105+
fromstring = _testcapi.pylong_fromstring
106+
self.assertEqual(fromstring(b'123', 10), (123, 3))
107+
self.assertEqual(fromstring(b'cafe', 16), (0xcafe, 4))
108+
self.assertEqual(fromstring(b'xyz', 36), (44027, 3))
109+
self.assertEqual(fromstring(b'123', 0), (123, 3))
110+
self.assertEqual(fromstring(b'0xcafe', 0), (0xcafe, 6))
111+
self.assertRaises(ValueError, fromstring, b'cafe', 0)
112+
self.assertEqual(fromstring(b'-123', 10), (-123, 4))
113+
self.assertEqual(fromstring(b' -123 ', 10), (-123, 6))
114+
self.assertEqual(fromstring(b'1_23', 10), (123, 4))
115+
self.assertRaises(ValueError, fromstring, b'- 123', 10)
116+
self.assertRaises(ValueError, fromstring, b'', 10)
117+
118+
self.assertRaises(ValueError, fromstring, b'123', 1)
119+
self.assertRaises(ValueError, fromstring, b'123', -1)
120+
self.assertRaises(ValueError, fromstring, b'123', 37)
121+
122+
self.assertRaises(ValueError, fromstring, '١٢٣٤٥٦٧٨٩٠'.encode(), 0)
123+
self.assertRaises(ValueError, fromstring, '١٢٣٤٥٦٧٨٩٠'.encode(), 16)
124+
125+
self.assertEqual(fromstring(b'123\x00', 0), (123, 3))
126+
self.assertEqual(fromstring(b'123\x00456', 0), (123, 3))
127+
self.assertEqual(fromstring(b'123\x00', 16), (0x123, 3))
128+
self.assertEqual(fromstring(b'123\x00456', 16), (0x123, 3))
129+
130+
# CRASHES fromstring(NULL, 0)
131+
# CRASHES fromstring(NULL, 16)
132+
133+
def test_long_fromunicodeobject(self):
134+
# Test PyLong_FromUnicodeObject()
135+
fromunicodeobject = _testcapi.pylong_fromunicodeobject
136+
self.assertEqual(fromunicodeobject('123', 10), 123)
137+
self.assertEqual(fromunicodeobject('cafe', 16), 0xcafe)
138+
self.assertEqual(fromunicodeobject('xyz', 36), 44027)
139+
self.assertEqual(fromunicodeobject('123', 0), 123)
140+
self.assertEqual(fromunicodeobject('0xcafe', 0), 0xcafe)
141+
self.assertRaises(ValueError, fromunicodeobject, 'cafe', 0)
142+
self.assertEqual(fromunicodeobject('-123', 10), -123)
143+
self.assertEqual(fromunicodeobject(' -123 ', 10), -123)
144+
self.assertEqual(fromunicodeobject('1_23', 10), 123)
145+
self.assertRaises(ValueError, fromunicodeobject, '- 123', 10)
146+
self.assertRaises(ValueError, fromunicodeobject, '', 10)
147+
148+
self.assertRaises(ValueError, fromunicodeobject, '123', 1)
149+
self.assertRaises(ValueError, fromunicodeobject, '123', -1)
150+
self.assertRaises(ValueError, fromunicodeobject, '123', 37)
151+
152+
self.assertEqual(fromunicodeobject('١٢٣٤٥٦٧٨٩٠', 0), 1234567890)
153+
self.assertEqual(fromunicodeobject('١٢٣٤٥٦٧٨٩٠', 16), 0x1234567890)
154+
155+
self.assertRaises(ValueError, fromunicodeobject, '123\x00', 0)
156+
self.assertRaises(ValueError, fromunicodeobject, '123\x00456', 0)
157+
self.assertRaises(ValueError, fromunicodeobject, '123\x00', 16)
158+
self.assertRaises(ValueError, fromunicodeobject, '123\x00456', 16)
159+
160+
# CRASHES fromunicodeobject(NULL, 0)
161+
# CRASHES fromunicodeobject(NULL, 16)
162+
163+
def test_long_aslong(self):
164+
# Test PyLong_AsLong() and PyLong_FromLong()
165+
aslong = _testcapi.pylong_aslong
166+
from _testcapi import LONG_MIN, LONG_MAX
167+
# round trip (object -> long -> object)
168+
for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234):
169+
with self.subTest(value=value):
170+
self.assertEqual(aslong(value), value)
171+
172+
self.assertEqual(aslong(IntSubclass(42)), 42)
173+
self.assertEqual(aslong(Index(42)), 42)
174+
self.assertEqual(aslong(MyIndexAndInt()), 10)
175+
176+
self.assertRaises(OverflowError, aslong, LONG_MIN - 1)
177+
self.assertRaises(OverflowError, aslong, LONG_MAX + 1)
178+
self.assertRaises(TypeError, aslong, 1.0)
F987 179+
self.assertRaises(TypeError, aslong, b'2')
180+
self.assertRaises(TypeError, aslong, '3')
181+
self.assertRaises(SystemError, aslong, NULL)
182+
183+
def test_long_aslongandoverflow(self):
184+
# Test PyLong_AsLongAndOverflow()
185+
aslongandoverflow = _testcapi.pylong_aslongandoverflow
186+
from _testcapi import LONG_MIN, LONG_MAX
187+
# round trip (object -> long -> object)
188+
for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234):
189+
with self.subTest(value=value):
190+
self.assertEqual(aslongandoverflow(value), (value, 0))
191+
192+
self.assertEqual(aslongandoverflow(IntSubclass(42)), (42, 0))
193+
self.assertEqual(aslongandoverflow(Index(42)), (42, 0))
194+
self.assertEqual(aslongandoverflow(MyIndexAndInt()), (10, 0))
195+
196+
self.assertEqual(aslongandoverflow(LONG_MIN - 1), (-1, -1))
197+
self.assertEqual(aslongandoverflow(LONG_MAX + 1), (-1, 1))
198+
# CRASHES aslongandoverflow(1.0)
199+
# CRASHES aslongandoverflow(NULL)
200+
201+
def test_long_asunsignedlong(self):
202+
# Test PyLong_AsUnsignedLong() and PyLong_FromUnsignedLong()
203+
asunsignedlong = _testcapi.pylong_asunsignedlong
204+
from _testcapi import ULONG_MAX
205+
# round trip (object -> unsigned long -> object)
206+
for value in (ULONG_MAX, 0, 1, 1234):
207+
with self.subTest(value=value):
208+
self.assertEqual(asunsignedlong(value), value)
209+
210+
self.assertEqual(asunsignedlong(IntSubclass(42)), 42)
211+
self.assertRaises(TypeError, asunsignedlong, Index(42))
212+
self.assertRaises(TypeError, asunsignedlong, MyIndexAndInt())
213+
214+
self.assertRaises(OverflowError, asunsignedlong, -1)
215+
self.assertRaises(OverflowError, asunsignedlong, ULONG_MAX + 1)
216+
self.assertRaises(TypeError, asunsignedlong, 1.0)
217+
self.assertRaises(TypeError, asunsignedlong, b'2')
218+
self.assertRaises(TypeError, asunsignedlong, '3')
219+
self.assertRaises(SystemError, asunsignedlong, NULL)
220+
221+
def test_long_asunsignedlongmask(self):
222+
# Test PyLong_AsUnsignedLongMask()
223+
asunsignedlongmask = _testcapi.pylong_asunsignedlongmask
224+
from _testcapi import ULONG_MAX
225+
# round trip (object -> unsigned long -> object)
226+
for value in (ULONG_MAX, 0, 1, 1234):
227+
with self.subTest(value=value):
228+
self.assertEqual(asunsignedlongmask(value), value)
229+
230+
self.assertEqual(asunsignedlongmask(IntSubclass(42)), 42)
231+
self.assertEqual(asunsignedlongmask(Index(42)), 42)
232+
self.assertEqual(asunsignedlongmask(MyIndexAndInt()), 10)
233+
234+
self.assertEqual(asunsignedlongmask(-1), ULONG_MAX)
235+
self.assertEqual(asunsignedlongmask(ULONG_MAX + 1), 0)
236+
self.assertRaises(TypeError, asunsignedlongmask, 1.0)
237+
self.assertRaises(TypeError, asunsignedlongmask, b'2')
238+
self.assertRaises(TypeError, asunsignedlongmask, '3')
239+
self.assertRaises(SystemError, asunsignedlongmask, NULL)
240+
241+
def test_long_aslonglong(self):
242+
# Test PyLong_AsLongLong() and PyLong_FromLongLong()
243+
aslonglong = _testcapi.pylong_aslonglong
244+
from _testcapi import LLONG_MIN, LLONG_MAX
245+
# round trip (object -> long long -> object)
246+
for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234):
247+
with self.subTest(value=value):
248+
self.assertEqual(aslonglong(value), value)
249+
250+
self.assertEqual(aslonglong(IntSubclass(42)), 42)
251+
self.assertEqual(aslonglong(Index(42)), 42)
252+
self.assertEqual(aslonglong(MyIndexAndInt()), 10)
253+
254+
self.assertRaises(OverflowError, aslonglong, LLONG_MIN - 1)
255+
self.assertRaises(OverflowError, aslonglong, LLONG_MAX + 1)
256+
self.assertRaises(TypeError, aslonglong, 1.0)
257+
self.assertRaises(TypeError, aslonglong, b'2')
258+
self.assertRaises(TypeError, aslonglong, '3')
259+
self.assertRaises(SystemError, aslonglong, NULL)
260+
261+
def test_long_aslonglongandoverflow(self):
262+
# Test PyLong_AsLongLongAndOverflow()
263+
aslonglongandoverflow = _testcapi.pylong_aslonglongandoverflow
264+
from _testcapi import LLONG_MIN, LLONG_MAX
265+
# round trip (object -> long long -> object)
266+
for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234):
267+
with self.subTest(value=value):
268+
self.assertEqual(aslonglongandoverflow(value), (value, 0))
269+
270+
self.assertEqual(aslonglongandoverflow(IntSubclass(42)), (42, 0))
271+
self.assertEqual(aslonglongandoverflow(Index(42)), (42, 0))
272+
self.assertEqual(aslonglongandoverflow(MyIndexAndInt()), (10, 0))
273+
274+
self.assertEqual(aslonglongandoverflow(LLONG_MIN - 1), (-1, -1))
275+
self.assertEqual(aslonglongandoverflow(LLONG_MAX + 1), (-1, 1))
276+
# CRASHES aslonglongandoverflow(1.0)
277+
# CRASHES aslonglongandoverflow(NULL)
278+
279+
def test_long_asunsignedlonglong(self):
280+
# Test PyLong_AsUnsignedLongLong() and PyLong_FromUnsignedLongLong()
281+
asunsignedlonglong = _testcapi.pylong_asunsignedlonglong
282+
from _testcapi import ULLONG_MAX
283+
# round trip (object -> unsigned long long -> object)
284+
for value in (ULLONG_MAX, 0, 1, 1234):
285+
with self.subTest(value=value):
286+
self.assertEqual(asunsignedlonglong(value), value)
287+
288+
self.assertEqual(asunsignedlonglong(IntSubclass(42)), 42)
289+
self.assertRaises(TypeError, asunsignedlonglong, Index(42))
290+
self.assertRaises(TypeError, asunsignedlonglong, MyIndexAndInt())
291+
292+
self.assertRaises(OverflowError, asunsignedlonglong, -1)
293+
self.assertRaises(OverflowError, asunsignedlonglong, ULLONG_MAX + 1)
294+
self.assertRaises(TypeError, asunsignedlonglong, 1.0)
295+
self.assertRaises(TypeError, asunsignedlonglong, b'2')
296+
self.assertRaises(TypeError, asunsignedlonglong, '3')
297+
self.assertRaises(SystemError, asunsignedlonglong, NULL)
298+
299+
def test_long_asunsignedlonglongmask(self):
300+
# Test PyLong_AsUnsignedLongLongMask()
301+
asunsignedlonglongmask = _testcapi.pylong_asunsignedlonglongmask
302+
from _testcapi import ULLONG_MAX
303+
# round trip (object -> unsigned long long -> object)
304+
for value in (ULLONG_MAX, 0, 1, 1234):
305+
with self.subTest(value=value):
306+
self.assertEqual(asunsignedlonglongmask(value), value)
307+
308+
self.assertEqual(asunsignedlonglongmask(IntSubclass(42)), 42)
309+
self.assertEqual(asunsignedlonglongmask(Index(42)), 42)
310+
self.assertEqual(asunsignedlonglongmask(MyIndexAndInt()), 10)
311+
312+
self.assertEqual(asunsignedlonglongmask(-1), ULLONG_MAX)
313+
self.assertEqual(asunsignedlonglongmask(ULLONG_MAX + 1), 0)
314+
self.assertRaises(TypeError, asunsignedlonglongmask, 1.0)
315+
self.assertRaises(TypeError, asunsignedlonglongmask, b'2')
316+
self.assertRaises(TypeError, asunsignedlonglongmask, '3')
317+
self.assertRaises(SystemError, asunsignedlonglongmask, NULL)
318+
319+
def test_long_as_ssize_t(self):
320+
# Test PyLong_AsSsize_t() and PyLong_FromSsize_t()
321+
as_ssize_t = _testcapi.pylong_as_ssize_t
322+
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
323+
# round trip (object -> Py_ssize_t -> object)
324+
for value in (PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1, 0, 1, 1234):
325+
with self.subTest(value=value):
326+
self.assertEqual(as_ssize_t(value), value)
327+
328+
self.assertEqual(as_ssize_t(IntSubclass(42)), 42)
329+
self.assertRaises(TypeError, as_ssize_t, Index(42))
330+
self.assertRaises(TypeError, as_ssize_t, MyIndexAndInt())
331+
332+
self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MIN - 1)
333+
self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MAX + 1)
334+
self.assertRaises(TypeError, as_ssize_t, 1.0)
335+
self.assertRaises(TypeError, as_ssize_t, b'2')
336+
self.assertRaises(TypeError, as_ssize_t, '3')
337+
self.assertRaises(SystemError, as_ssize_t, NULL)
338+
339+
def test_long_as_size_t(self):
340+
# Test PyLong_AsSize_t() and PyLong_FromSize_t()
341+
as_size_t = _testcapi.pylong_as_size_t
342+
from _testcapi import SIZE_MAX
343+
# round trip (object -> size_t -> object)
344+
for value in (SIZE_MAX, 0, 1, 1234):
345+
with self.subTest(value=value):
346+
self.assertEqual(as_size_t(value), value)
347+
348+
self.assertEqual(as_size_t(IntSubclass(42)), 42)
349+
self.assertRaises(TypeError, as_size_t, Index(42))
350+
self.assertRaises(TypeError, as_size_t, MyIndexAndInt())
351+
352+
self.assertRaises(OverflowError, as_size_t, -1)
353+
self.assertRaises(OverflowError, as_size_t, SIZE_MAX + 1)
354+
self.assertRaises(TypeError, as_size_t, 1.0)
355+
self.assertRaises(TypeError, as_size_t, b'2')
356+
self.assertRaises(TypeError, as_size_t, '3')
357+
self.assertRaises(SystemError, as_size_t, NULL)
358+
359+
def test_long_asdouble(self):
360+
# Test PyLong_AsDouble()
361+
asdouble = _testcapi.pylong_asdouble
362+
MAX = int(sys.float_info.max)
363+
for value in (-MAX, MAX, -1, 0, 1, 1234):
364+
with self.subTest(value=value):
365+
self.assertEqual(asdouble(value), float(value))
366+
self.assertIsInstance(asdouble(value), float)
367+
368+
self.assertEqual(asdouble(IntSubclass(42)), 42.0)
369+
self.assertRaises(TypeError, asdouble, Index(42))
370+
self.assertRaises(TypeError, asdouble, MyIndexAndInt())
371+
372+
self.assertRaises(OverflowError, asdouble, 2 * MAX)
373+
self.assertRaises(OverflowError, asdouble, -2 * MAX)
374+
self.assertRaises(TypeError, asdouble, 1.0)
375+
self.assertRaises(TypeError, asdouble, b'2')
376+
self.assertRaises(TypeError, asdouble, '3')
377+
self.assertRaises(SystemError, asdouble, NULL)
378+
379+
def test_long_asvoidptr(self):
380+
# Test PyLong_AsVoidPtr()
381+
fromvoidptr = _testcapi.pylong_fromvoidptr
382+
asvoidptr = _testcapi.pylong_asvoidptr
383+
obj = object()
384+
x = fromvoidptr(obj)
385+
y = fromvoidptr(NULL)
386+
self.assertIs(asvoidptr(x), obj)
387+
self.assertIs(asvoidptr(y), NULL)
388+
self.assertIs(asvoidptr(IntSubclass(x)), obj)
389+
390+
# negative values
391+
M = (1 << _testcapi.SIZEOF_VOID_P * 8)
392+
if x >= M//2:
393+
self.assertIs(asvoidptr(x - M), obj)
394+
if y >= M//2:
395+
self.assertIs(asvoidptr(y - M), NULL)
396+
397+
self.assertRaises(TypeError, asvoidptr, Index(x))
398+
self.assertRaises(TypeError, asvoidptr, object())
399+
self.assertRaises(OverflowError, asvoidptr, 2**1000)
400+
self.assertRaises(OverflowError, asvoidptr, -2**1000)
401+
# CRASHES asvoidptr(NULL)
402+
37403

38404
if __name__ == "__main__":
39405
unittest.main()

0 commit comments

Comments
 (0)
0