2023-08-07 12:51:43 -03:00
|
|
|
import unittest
|
|
|
|
from collections import OrderedDict
|
2023-11-07 09:58:04 -04:00
|
|
|
from test import support
|
2023-11-04 06:40:46 -03:00
|
|
|
from test.support import import_helper
|
2023-08-07 12:51:43 -03:00
|
|
|
|
2023-11-04 06:40:46 -03:00
|
|
|
_testcapi = import_helper.import_module('_testcapi')
|
2024-03-19 07:44:13 -03:00
|
|
|
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
|
2023-11-04 06:40:46 -03:00
|
|
|
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
NULL = None
|
|
|
|
|
2023-11-29 11:37:05 -04:00
|
|
|
class StrSubclass(str):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class BytesSubclass(bytes):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class WithStr:
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = value
|
|
|
|
def __str__(self):
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
class WithRepr:
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
class WithBytes:
|
|
|
|
def __init__(self, value):
|
|
|
|
self.value = value
|
|
|
|
def __bytes__(self):
|
|
|
|
return self.value
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
class TestObject:
|
|
|
|
@property
|
|
|
|
def evil(self):
|
|
|
|
raise RuntimeError('do not get evil')
|
|
|
|
@evil.setter
|
|
|
|
def evil(self, value):
|
|
|
|
raise RuntimeError('do not set evil')
|
|
|
|
@evil.deleter
|
|
|
|
def evil(self):
|
|
|
|
raise RuntimeError('do not del evil')
|
|
|
|
|
|
|
|
class ProxyGetItem:
|
|
|
|
def __init__(self, obj):
|
|
|
|
self.obj = obj
|
|
|
|
def __getitem__(self, key):
|
|
|
|
return self.obj[key]
|
|
|
|
|
|
|
|
class ProxySetItem:
|
|
|
|
def __init__(self, obj):
|
|
|
|
self.obj = obj
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
self.obj[key] = value
|
|
|
|
|
|
|
|
class ProxyDelItem:
|
|
|
|
def __init__(self, obj):
|
|
|
|
self.obj = obj
|
|
|
|
def __delitem__(self, key):
|
|
|
|
del self.obj[key]
|
|
|
|
|
|
|
|
def gen():
|
|
|
|
yield 'a'
|
|
|
|
yield 'b'
|
|
|
|
yield 'c'
|
|
|
|
|
|
|
|
|
|
|
|
class CAPITest(unittest.TestCase):
|
2023-11-29 11:37:05 -04:00
|
|
|
def assertTypedEqual(self, actual, expected):
|
|
|
|
self.assertIs(type(actual), type(expected))
|
|
|
|
self.assertEqual(actual, expected)
|
|
|
|
|
|
|
|
def test_object_str(self):
|
|
|
|
# Test PyObject_Str()
|
2024-03-19 07:44:13 -03:00
|
|
|
object_str = _testlimitedcapi.object_str
|
2023-11-29 11:37:05 -04:00
|
|
|
self.assertTypedEqual(object_str(''), '')
|
|
|
|
self.assertTypedEqual(object_str('abc'), 'abc')
|
|
|
|
self.assertTypedEqual(object_str('\U0001f40d'), '\U0001f40d')
|
|
|
|
self.assertTypedEqual(object_str(StrSubclass('abc')), 'abc')
|
|
|
|
self.assertTypedEqual(object_str(WithStr('abc')), 'abc')
|
|
|
|
self.assertTypedEqual(object_str(WithStr(StrSubclass('abc'))), StrSubclass('abc'))
|
|
|
|
self.assertTypedEqual(object_str(WithRepr('<abc>')), '<abc>')
|
|
|
|
self.assertTypedEqual(object_str(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
|
|
|
|
self.assertTypedEqual(object_str(NULL), '<NULL>')
|
|
|
|
|
|
|
|
def test_object_repr(self):
|
|
|
|
# Test PyObject_Repr()
|
2024-03-19 07:44:13 -03:00
|
|
|
object_repr = _testlimitedcapi.object_repr
|
2023-11-29 11:37:05 -04:00
|
|
|
self.assertTypedEqual(object_repr(''), "''")
|
|
|
|
self.assertTypedEqual(object_repr('abc'), "'abc'")
|
|
|
|
self.assertTypedEqual(object_repr('\U0001f40d'), "'\U0001f40d'")
|
|
|
|
self.assertTypedEqual(object_repr(StrSubclass('abc')), "'abc'")
|
|
|
|
self.assertTypedEqual(object_repr(WithRepr('<abc>')), '<abc>')
|
|
|
|
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
|
|
|
|
self.assertTypedEqual(object_repr(WithRepr('<\U0001f40d>')), '<\U0001f40d>')
|
|
|
|
self.assertTypedEqual(object_repr(WithRepr(StrSubclass('<\U0001f40d>'))), StrSubclass('<\U0001f40d>'))
|
|
|
|
self.assertTypedEqual(object_repr(NULL), '<NULL>')
|
|
|
|
|
|
|
|
def test_object_ascii(self):
|
|
|
|
# Test PyObject_ASCII()
|
2024-03-19 07:44:13 -03:00
|
|
|
object_ascii = _testlimitedcapi.object_ascii
|
2023-11-29 11:37:05 -04:00
|
|
|
self.assertTypedEqual(object_ascii(''), "''")
|
|
|
|
self.assertTypedEqual(object_ascii('abc'), "'abc'")
|
|
|
|
self.assertTypedEqual(object_ascii('\U0001f40d'), r"'\U0001f40d'")
|
|
|
|
self.assertTypedEqual(object_ascii(StrSubclass('abc')), "'abc'")
|
|
|
|
self.assertTypedEqual(object_ascii(WithRepr('<abc>')), '<abc>')
|
|
|
|
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<abc>'))), StrSubclass('<abc>'))
|
|
|
|
self.assertTypedEqual(object_ascii(WithRepr('<\U0001f40d>')), r'<\U0001f40d>')
|
|
|
|
self.assertTypedEqual(object_ascii(WithRepr(StrSubclass('<\U0001f40d>'))), r'<\U0001f40d>')
|
|
|
|
self.assertTypedEqual(object_ascii(NULL), '<NULL>')
|
|
|
|
|
|
|
|
def test_object_bytes(self):
|
|
|
|
# Test PyObject_Bytes()
|
2024-03-19 07:44:13 -03:00
|
|
|
object_bytes = _testlimitedcapi.object_bytes
|
2023-11-29 11:37:05 -04:00
|
|
|
self.assertTypedEqual(object_bytes(b''), b'')
|
|
|
|
self.assertTypedEqual(object_bytes(b'abc'), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes(BytesSubclass(b'abc')), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes(WithBytes(b'abc')), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes(WithBytes(BytesSubclass(b'abc'))), BytesSubclass(b'abc'))
|
|
|
|
self.assertTypedEqual(object_bytes(bytearray(b'abc')), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes(memoryview(b'abc')), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes([97, 98, 99]), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes((97, 98, 99)), b'abc')
|
|
|
|
self.assertTypedEqual(object_bytes(iter([97, 98, 99])), b'abc')
|
|
|
|
self.assertRaises(TypeError, object_bytes, WithBytes(bytearray(b'abc')))
|
|
|
|
self.assertRaises(TypeError, object_bytes, WithBytes([97, 98, 99]))
|
|
|
|
self.assertRaises(TypeError, object_bytes, 3)
|
|
|
|
self.assertRaises(TypeError, object_bytes, 'abc')
|
|
|
|
self.assertRaises(TypeError, object_bytes, object())
|
|
|
|
self.assertTypedEqual(object_bytes(NULL), b'<NULL>')
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
def test_object_getattr(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xgetattr = _testlimitedcapi.object_getattr
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 11
|
|
|
|
setattr(obj, '\U0001f40d', 22)
|
|
|
|
self.assertEqual(xgetattr(obj, 'a'), 11)
|
|
|
|
self.assertRaises(AttributeError, xgetattr, obj, 'b')
|
|
|
|
self.assertEqual(xgetattr(obj, '\U0001f40d'), 22)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, xgetattr, obj, 'evil')
|
|
|
|
self.assertRaises(TypeError, xgetattr, obj, 1)
|
|
|
|
# CRASHES xgetattr(obj, NULL)
|
|
|
|
# CRASHES xgetattr(NULL, 'a')
|
|
|
|
|
|
|
|
def test_object_getattrstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
getattrstring = _testlimitedcapi.object_getattrstring
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 11
|
|
|
|
setattr(obj, '\U0001f40d', 22)
|
|
|
|
self.assertEqual(getattrstring(obj, b'a'), 11)
|
|
|
|
self.assertRaises(AttributeError, getattrstring, obj, b'b')
|
|
|
|
self.assertEqual(getattrstring(obj, '\U0001f40d'.encode()), 22)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, getattrstring, obj, b'evil')
|
|
|
|
self.assertRaises(UnicodeDecodeError, getattrstring, obj, b'\xff')
|
|
|
|
# CRASHES getattrstring(obj, NULL)
|
|
|
|
# CRASHES getattrstring(NULL, b'a')
|
|
|
|
|
|
|
|
def test_object_getoptionalattr(self):
|
|
|
|
getoptionalattr = _testcapi.object_getoptionalattr
|
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 11
|
|
|
|
setattr(obj, '\U0001f40d', 22)
|
|
|
|
self.assertEqual(getoptionalattr(obj, 'a'), 11)
|
|
|
|
self.assertIs(getoptionalattr(obj, 'b'), AttributeError)
|
|
|
|
self.assertEqual(getoptionalattr(obj, '\U0001f40d'), 22)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, getoptionalattr, obj, 'evil')
|
|
|
|
self.assertRaises(TypeError, getoptionalattr, obj, 1)
|
|
|
|
# CRASHES getoptionalattr(obj, NULL)
|
|
|
|
# CRASHES getoptionalattr(NULL, 'a')
|
|
|
|
|
|
|
|
def test_object_getoptionalattrstring(self):
|
|
|
|
getoptionalattrstring = _testcapi.object_getoptionalattrstring
|
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 11
|
|
|
|
setattr(obj, '\U0001f40d', 22)
|
|
|
|
self.assertEqual(getoptionalattrstring(obj, b'a'), 11)
|
|
|
|
self.assertIs(getoptionalattrstring(obj, b'b'), AttributeError)
|
|
|
|
self.assertEqual(getoptionalattrstring(obj, '\U0001f40d'.encode()), 22)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, getoptionalattrstring, obj, b'evil')
|
|
|
|
self.assertRaises(UnicodeDecodeError, getoptionalattrstring, obj, b'\xff')
|
|
|
|
# CRASHES getoptionalattrstring(obj, NULL)
|
|
|
|
# CRASHES getoptionalattrstring(NULL, b'a')
|
|
|
|
|
|
|
|
def test_object_hasattr(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xhasattr = _testlimitedcapi.object_hasattr
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
self.assertTrue(xhasattr(obj, 'a'))
|
|
|
|
self.assertFalse(xhasattr(obj, 'b'))
|
|
|
|
self.assertTrue(xhasattr(obj, '\U0001f40d'))
|
|
|
|
|
2023-11-07 09:58:04 -04:00
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(xhasattr(obj, 'evil'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, RuntimeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'do not get evil')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(xhasattr(obj, 1))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"attribute name must be string, not 'int'")
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
# CRASHES xhasattr(obj, NULL)
|
|
|
|
# CRASHES xhasattr(NULL, 'a')
|
|
|
|
|
|
|
|
def test_object_hasattrstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
hasattrstring = _testlimitedcapi.object_hasattrstring
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
self.assertTrue(hasattrstring(obj, b'a'))
|
|
|
|
self.assertFalse(hasattrstring(obj, b'b'))
|
|
|
|
self.assertTrue(hasattrstring(obj, '\U0001f40d'.encode()))
|
|
|
|
|
2023-11-07 09:58:04 -04:00
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(hasattrstring(obj, b'evil'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, RuntimeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'do not get evil')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(hasattrstring(obj, b'\xff'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, UnicodeDecodeError)
|
|
|
|
self.assertRegex(str(cm.unraisable.exc_value),
|
|
|
|
"'utf-8' codec can't decode")
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
# CRASHES hasattrstring(obj, NULL)
|
|
|
|
# CRASHES hasattrstring(NULL, b'a')
|
|
|
|
|
2023-09-17 08:23:31 -03:00
|
|
|
def test_object_hasattrwitherror(self):
|
|
|
|
xhasattr = _testcapi.object_hasattrwitherror
|
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
self.assertTrue(xhasattr(obj, 'a'))
|
|
|
|
self.assertFalse(xhasattr(obj, 'b'))
|
|
|
|
self.assertTrue(xhasattr(obj, '\U0001f40d'))
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, xhasattr, obj, 'evil')
|
|
|
|
self.assertRaises(TypeError, xhasattr, obj, 1)
|
|
|
|
# CRASHES xhasattr(obj, NULL)
|
|
|
|
# CRASHES xhasattr(NULL, 'a')
|
|
|
|
|
|
|
|
def test_object_hasattrstringwitherror(self):
|
|
|
|
hasattrstring = _testcapi.object_hasattrstringwitherror
|
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
self.assertTrue(hasattrstring(obj, b'a'))
|
|
|
|
self.assertFalse(hasattrstring(obj, b'b'))
|
|
|
|
self.assertTrue(hasattrstring(obj, '\U0001f40d'.encode()))
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, hasattrstring, obj, b'evil')
|
|
|
|
self.assertRaises(UnicodeDecodeError, hasattrstring, obj, b'\xff')
|
|
|
|
# CRASHES hasattrstring(obj, NULL)
|
|
|
|
# CRASHES hasattrstring(NULL, b'a')
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
def test_object_setattr(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xsetattr = _testlimitedcapi.object_setattr
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
xsetattr(obj, 'a', 5)
|
|
|
|
self.assertEqual(obj.a, 5)
|
|
|
|
xsetattr(obj, '\U0001f40d', 8)
|
|
|
|
self.assertEqual(getattr(obj, '\U0001f40d'), 8)
|
|
|
|
|
|
|
|
# PyObject_SetAttr(obj, attr_name, NULL) removes the attribute
|
|
|
|
xsetattr(obj, 'a', NULL)
|
|
|
|
self.assertFalse(hasattr(obj, 'a'))
|
|
|
|
self.assertRaises(AttributeError, xsetattr, obj, 'b', NULL)
|
|
|
|
self.assertRaises(RuntimeError, xsetattr, obj, 'evil', NULL)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, xsetattr, obj, 'evil', 'good')
|
|
|
|
self.assertRaises(AttributeError, xsetattr, 42, 'a', 5)
|
|
|
|
self.assertRaises(TypeError, xsetattr, obj, 1, 5)
|
|
|
|
# CRASHES xsetattr(obj, NULL, 5)
|
|
|
|
# CRASHES xsetattr(NULL, 'a', 5)
|
|
|
|
|
|
|
|
def test_object_setattrstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
setattrstring = _testlimitedcapi.object_setattrstring
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
setattrstring(obj, b'a', 5)
|
|
|
|
self.assertEqual(obj.a, 5)
|
|
|
|
setattrstring(obj, '\U0001f40d'.encode(), 8)
|
|
|
|
self.assertEqual(getattr(obj, '\U0001f40d'), 8)
|
|
|
|
|
|
|
|
# PyObject_SetAttrString(obj, attr_name, NULL) removes the attribute
|
|
|
|
setattrstring(obj, b'a', NULL)
|
|
|
|
self.assertFalse(hasattr(obj, 'a'))
|
|
|
|
self.assertRaises(AttributeError, setattrstring, obj, b'b', NULL)
|
|
|
|
self.assertRaises(RuntimeError, setattrstring, obj, b'evil', NULL)
|
|
|
|
|
|
|
|
self.assertRaises(RuntimeError, setattrstring, obj, b'evil', 'good')
|
|
|
|
self.assertRaises(AttributeError, setattrstring, 42, b'a', 5)
|
|
|
|
self.assertRaises(TypeError, setattrstring, obj, 1, 5)
|
|
|
|
self.assertRaises(UnicodeDecodeError, setattrstring, obj, b'\xff', 5)
|
|
|
|
# CRASHES setattrstring(obj, NULL, 5)
|
|
|
|
# CRASHES setattrstring(NULL, b'a', 5)
|
|
|
|
|
|
|
|
def test_object_delattr(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xdelattr = _testlimitedcapi.object_delattr
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
xdelattr(obj, 'a')
|
|
|
|
self.assertFalse(hasattr(obj, 'a'))
|
|
|
|
self.assertRaises(AttributeError, xdelattr, obj, 'b')
|
|
|
|
xdelattr(obj, '\U0001f40d')
|
|
|
|
self.assertFalse(hasattr(obj, '\U0001f40d'))
|
|
|
|
|
|
|
|
self.assertRaises(AttributeError, xdelattr, 42, 'numerator')
|
|
|
|
self.assertRaises(RuntimeError, xdelattr, obj, 'evil')
|
|
|
|
self.assertRaises(TypeError, xdelattr, obj, 1)
|
|
|
|
# CRASHES xdelattr(obj, NULL)
|
|
|
|
# CRASHES xdelattr(NULL, 'a')
|
|
|
|
|
|
|
|
def test_object_delattrstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
delattrstring = _testlimitedcapi.object_delattrstring
|
2023-08-07 12:51:43 -03:00
|
|
|
obj = TestObject()
|
|
|
|
obj.a = 1
|
|
|
|
setattr(obj, '\U0001f40d', 2)
|
|
|
|
delattrstring(obj, b'a')
|
|
|
|
self.assertFalse(hasattr(obj, 'a'))
|
|
|
|
self.assertRaises(AttributeError, delattrstring, obj, b'b')
|
|
|
|
delattrstring(obj, '\U0001f40d'.encode())
|
|
|
|
self.assertFalse(hasattr(obj, '\U0001f40d'))
|
|
|
|
|
|
|
|
self.assertRaises(AttributeError, delattrstring, 42, b'numerator')
|
|
|
|
self.assertRaises(RuntimeError, delattrstring, obj, b'evil')
|
|
|
|
self.assertRaises(UnicodeDecodeError, delattrstring, obj, b'\xff')
|
|
|
|
# CRASHES delattrstring(obj, NULL)
|
|
|
|
# CRASHES delattrstring(NULL, b'a')
|
|
|
|
|
|
|
|
|
|
|
|
def test_mapping_check(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
check = _testlimitedcapi.mapping_check
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertTrue(check({1: 2}))
|
|
|
|
self.assertTrue(check([1, 2]))
|
|
|
|
self.assertTrue(check((1, 2)))
|
|
|
|
self.assertTrue(check('abc'))
|
|
|
|
self.assertTrue(check(b'abc'))
|
|
|
|
self.assertFalse(check(42))
|
|
|
|
self.assertFalse(check(object()))
|
|
|
|
self.assertFalse(check(NULL))
|
|
|
|
|
|
|
|
def test_mapping_size(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
for size in _testlimitedcapi.mapping_size, _testlimitedcapi.mapping_length:
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(size({1: 2}), 1)
|
|
|
|
self.assertEqual(size([1, 2]), 2)
|
|
|
|
self.assertEqual(size((1, 2)), 2)
|
|
|
|
self.assertEqual(size('abc'), 3)
|
|
|
|
self.assertEqual(size(b'abc'), 3)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, size, 42)
|
|
|
|
self.assertRaises(TypeError, size, object())
|
|
|
|
self.assertRaises(SystemError, size, NULL)
|
|
|
|
|
|
|
|
def test_object_getitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
getitem = _testlimitedcapi.object_getitem
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertEqual(getitem(dct, 'a'), 1)
|
|
|
|
self.assertRaises(KeyError, getitem, dct, 'b')
|
|
|
|
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertEqual(getitem(dct2, 'a'), 1)
|
|
|
|
self.assertRaises(KeyError, getitem, dct2, 'b')
|
|
|
|
|
|
|
|
self.assertEqual(getitem(['a', 'b', 'c'], 1), 'b')
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, getitem, 42, 'a')
|
|
|
|
self.assertRaises(TypeError, getitem, {}, []) # unhashable
|
|
|
|
self.assertRaises(SystemError, getitem, {}, NULL)
|
|
|
|
self.assertRaises(IndexError, getitem, [], 1)
|
|
|
|
self.assertRaises(TypeError, getitem, [], 'a')
|
|
|
|
self.assertRaises(SystemError, getitem, NULL, 'a')
|
|
|
|
|
|
|
|
def test_mapping_getitemstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
getitemstring = _testlimitedcapi.mapping_getitemstring
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertEqual(getitemstring(dct, b'a'), 1)
|
|
|
|
self.assertRaises(KeyError, getitemstring, dct, b'b')
|
|
|
|
self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertEqual(getitemstring(dct2, b'a'), 1)
|
|
|
|
self.assertRaises(KeyError, getitemstring, dct2, b'b')
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, getitemstring, 42, b'a')
|
|
|
|
self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff')
|
|
|
|
self.assertRaises(SystemError, getitemstring, {}, NULL)
|
|
|
|
self.assertRaises(TypeError, getitemstring, [], b'a')
|
|
|
|
self.assertRaises(SystemError, getitemstring, NULL, b'a')
|
|
|
|
|
2023-09-06 16:47:38 -03:00
|
|
|
def test_mapping_getoptionalitem(self):
|
|
|
|
getitem = _testcapi.mapping_getoptionalitem
|
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertEqual(getitem(dct, 'a'), 1)
|
|
|
|
self.assertEqual(getitem(dct, 'b'), KeyError)
|
|
|
|
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertEqual(getitem(dct2, 'a'), 1)
|
|
|
|
self.assertEqual(getitem(dct2, 'b'), KeyError)
|
|
|
|
|
|
|
|
self.assertEqual(getitem(['a', 'b', 'c'], 1), 'b')
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, getitem, 42, 'a')
|
|
|
|
self.assertRaises(TypeError, getitem, {}, []) # unhashable
|
|
|
|
self.assertRaises(IndexError, getitem, [], 1)
|
|
|
|
self.assertRaises(TypeError, getitem, [], 'a')
|
|
|
|
# CRASHES getitem({}, NULL)
|
|
|
|
# CRASHES getitem(NULL, 'a')
|
|
|
|
|
|
|
|
def test_mapping_getoptionalitemstring(self):
|
|
|
|
getitemstring = _testcapi.mapping_getoptionalitemstring
|
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertEqual(getitemstring(dct, b'a'), 1)
|
|
|
|
self.assertEqual(getitemstring(dct, b'b'), KeyError)
|
|
|
|
self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertEqual(getitemstring(dct2, b'a'), 1)
|
|
|
|
self.assertEqual(getitemstring(dct2, b'b'), KeyError)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, getitemstring, 42, b'a')
|
|
|
|
self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff')
|
|
|
|
self.assertRaises(SystemError, getitemstring, {}, NULL)
|
|
|
|
self.assertRaises(TypeError, getitemstring, [], b'a')
|
|
|
|
# CRASHES getitemstring(NULL, b'a')
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
def test_mapping_haskey(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
haskey = _testlimitedcapi.mapping_haskey
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertTrue(haskey(dct, 'a'))
|
|
|
|
self.assertFalse(haskey(dct, 'b'))
|
|
|
|
self.assertTrue(haskey(dct, '\U0001f40d'))
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertTrue(haskey(dct2, 'a'))
|
|
|
|
self.assertFalse(haskey(dct2, 'b'))
|
|
|
|
|
|
|
|
self.assertTrue(haskey(['a', 'b', 'c'], 1))
|
|
|
|
|
2023-11-07 09:58:04 -04:00
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey(42, 'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"'int' object is not subscriptable")
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey({}, []))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"unhashable type: 'list'")
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey([], 1))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, IndexError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'list index out of range')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey([], 'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'list indices must be integers or slices, not str')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey({}, NULL))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, SystemError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'null argument to internal routine')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskey(NULL, 'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, SystemError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'null argument to internal routine')
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
def test_mapping_haskeystring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
haskeystring = _testlimitedcapi.mapping_haskeystring
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertTrue(haskeystring(dct, b'a'))
|
|
|
|
self.assertFalse(haskeystring(dct, b'b'))
|
|
|
|
self.assertTrue(haskeystring(dct, '\U0001f40d'.encode()))
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertTrue(haskeystring(dct2, b'a'))
|
|
|
|
self.assertFalse(haskeystring(dct2, b'b'))
|
|
|
|
|
2023-11-07 09:58:04 -04:00
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskeystring(42, b'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"'int' object is not subscriptable")
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskeystring({}, b'\xff'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, UnicodeDecodeError)
|
|
|
|
self.assertRegex(str(cm.unraisable.exc_value),
|
|
|
|
"'utf-8' codec can't decode")
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskeystring({}, NULL))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, SystemError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"null argument to internal routine")
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskeystring([], b'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, TypeError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
'list indices must be integers or slices, not str')
|
|
|
|
|
|
|
|
with support.catch_unraisable_exception() as cm:
|
|
|
|
self.assertFalse(haskeystring(NULL, b'a'))
|
|
|
|
self.assertEqual(cm.unraisable.exc_type, SystemError)
|
|
|
|
self.assertEqual(str(cm.unraisable.exc_value),
|
|
|
|
"null argument to internal routine")
|
2023-08-07 12:51:43 -03:00
|
|
|
|
2023-09-17 08:23:31 -03:00
|
|
|
def test_mapping_haskeywitherror(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
haskey = _testlimitedcapi.mapping_haskeywitherror
|
2023-09-17 08:23:31 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertTrue(haskey(dct, 'a'))
|
|
|
|
self.assertFalse(haskey(dct, 'b'))
|
|
|
|
self.assertTrue(haskey(dct, '\U0001f40d'))
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertTrue(haskey(dct2, 'a'))
|
|
|
|
self.assertFalse(haskey(dct2, 'b'))
|
|
|
|
|
|
|
|
self.assertTrue(haskey(['a', 'b', 'c'], 1))
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, haskey, 42, 'a')
|
|
|
|
self.assertRaises(TypeError, haskey, {}, []) # unhashable
|
|
|
|
self.assertRaises(IndexError, haskey, [], 1)
|
|
|
|
self.assertRaises(TypeError, haskey, [], 'a')
|
|
|
|
|
|
|
|
# CRASHES haskey({}, NULL))
|
|
|
|
# CRASHES haskey(NULL, 'a'))
|
|
|
|
|
|
|
|
def test_mapping_haskeystringwitherror(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
haskeystring = _testlimitedcapi.mapping_haskeystringwitherror
|
2023-09-17 08:23:31 -03:00
|
|
|
dct = {'a': 1, '\U0001f40d': 2}
|
|
|
|
self.assertTrue(haskeystring(dct, b'a'))
|
|
|
|
self.assertFalse(haskeystring(dct, b'b'))
|
|
|
|
self.assertTrue(haskeystring(dct, '\U0001f40d'.encode()))
|
|
|
|
|
|
|
|
dct2 = ProxyGetItem(dct)
|
|
|
|
self.assertTrue(haskeystring(dct2, b'a'))
|
|
|
|
self.assertFalse(haskeystring(dct2, b'b'))
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, haskeystring, 42, b'a')
|
|
|
|
self.assertRaises(UnicodeDecodeError, haskeystring, {}, b'\xff')
|
|
|
|
self.assertRaises(SystemError, haskeystring, {}, NULL)
|
|
|
|
self.assertRaises(TypeError, haskeystring, [], b'a')
|
|
|
|
# CRASHES haskeystring(NULL, b'a')
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
def test_object_setitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
setitem = _testlimitedcapi.object_setitem
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {}
|
|
|
|
setitem(dct, 'a', 5)
|
|
|
|
self.assertEqual(dct, {'a': 5})
|
|
|
|
setitem(dct, '\U0001f40d', 8)
|
|
|
|
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
|
|
|
|
|
|
|
|
dct = {}
|
|
|
|
dct2 = ProxySetItem(dct)
|
|
|
|
setitem(dct2, 'a', 5)
|
|
|
|
self.assertEqual(dct, {'a': 5})
|
|
|
|
|
|
|
|
lst = ['a', 'b', 'c']
|
|
|
|
setitem(lst, 1, 'x')
|
|
|
|
self.assertEqual(lst, ['a', 'x', 'c'])
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, setitem, 42, 'a', 5)
|
|
|
|
self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable
|
|
|
|
self.assertRaises(SystemError, setitem, {}, NULL, 5)
|
|
|
|
self.assertRaises(SystemError, setitem, {}, 'a', NULL)
|
|
|
|
self.assertRaises(IndexError, setitem, [], 1, 5)
|
|
|
|
self.assertRaises(TypeError, setitem, [], 'a', 5)
|
|
|
|
self.assertRaises(TypeError, setitem, (), 1, 5)
|
|
|
|
self.assertRaises(SystemError, setitem, NULL, 'a', 5)
|
|
|
|
|
|
|
|
def test_mapping_setitemstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
setitemstring = _testlimitedcapi.mapping_setitemstring
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {}
|
|
|
|
setitemstring(dct, b'a', 5)
|
|
|
|
self.assertEqual(dct, {'a': 5})
|
|
|
|
setitemstring(dct, '\U0001f40d'.encode(), 8)
|
|
|
|
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
|
|
|
|
|
|
|
|
dct = {}
|
|
|
|
dct2 = ProxySetItem(dct)
|
|
|
|
setitemstring(dct2, b'a', 5)
|
|
|
|
self.assertEqual(dct, {'a': 5})
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, setitemstring, 42, b'a', 5)
|
|
|
|
self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5)
|
|
|
|
self.assertRaises(SystemError, setitemstring, {}, NULL, 5)
|
|
|
|
self.assertRaises(SystemError, setitemstring, {}, b'a', NULL)
|
|
|
|
self.assertRaises(TypeError, setitemstring, [], b'a', 5)
|
|
|
|
self.assertRaises(SystemError, setitemstring, NULL, b'a', 5)
|
|
|
|
|
|
|
|
def test_object_delitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
for delitem in _testlimitedcapi.object_delitem, _testlimitedcapi.mapping_delitem:
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
|
|
|
|
delitem(dct, 'a')
|
|
|
|
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
|
|
|
|
self.assertRaises(KeyError, delitem, dct, 'b')
|
|
|
|
delitem(dct, '\U0001f40d')
|
|
|
|
self.assertEqual(dct, {'c': 2})
|
|
|
|
|
|
|
|
dct = {'a': 1, 'c': 2}
|
|
|
|
dct2 = ProxyDelItem(dct)
|
|
|
|
delitem(dct2, 'a')
|
|
|
|
self.assertEqual(dct, {'c': 2})
|
|
|
|
self.assertRaises(KeyError, delitem, dct2, 'b')
|
|
|
|
|
|
|
|
lst = ['a', 'b', 'c']
|
|
|
|
delitem(lst, 1)
|
|
|
|
self.assertEqual(lst, ['a', 'c'])
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, delitem, 42, 'a')
|
|
|
|
self.assertRaises(TypeError, delitem, {}, []) # unhashable
|
|
|
|
self.assertRaises(SystemError, delitem, {}, NULL)
|
|
|
|
self.assertRaises(IndexError, delitem, [], 1)
|
|
|
|
self.assertRaises(TypeError, delitem, [], 'a')
|
|
|
|
self.assertRaises(SystemError, delitem, NULL, 'a')
|
|
|
|
|
|
|
|
def test_mapping_delitemstring(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
delitemstring = _testlimitedcapi.mapping_delitemstring
|
2023-08-07 12:51:43 -03:00
|
|
|
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
|
|
|
|
delitemstring(dct, b'a')
|
|
|
|
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
|
|
|
|
self.assertRaises(KeyError, delitemstring, dct, b'b')
|
|
|
|
delitemstring(dct, '\U0001f40d'.encode())
|
|
|
|
self.assertEqual(dct, {'c': 2})
|
|
|
|
|
|
|
|
dct = {'a': 1, 'c': 2}
|
|
|
|
dct2 = ProxyDelItem(dct)
|
|
|
|
delitemstring(dct2, b'a')
|
|
|
|
self.assertEqual(dct, {'c': 2})
|
|
|
|
self.assertRaises(KeyError, delitemstring, dct2, b'b')
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, delitemstring, 42, b'a')
|
|
|
|
self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff')
|
|
|
|
self.assertRaises(SystemError, delitemstring, {}, NULL)
|
|
|
|
self.assertRaises(TypeError, delitemstring, [], b'a')
|
|
|
|
self.assertRaises(SystemError, delitemstring, NULL, b'a')
|
|
|
|
|
|
|
|
def test_mapping_keys_valuesitems(self):
|
|
|
|
class Mapping1(dict):
|
|
|
|
def keys(self):
|
|
|
|
return list(super().keys())
|
|
|
|
def values(self):
|
|
|
|
return list(super().values())
|
|
|
|
def items(self):
|
|
|
|
return list(super().items())
|
|
|
|
class Mapping2(dict):
|
|
|
|
def keys(self):
|
|
|
|
return tuple(super().keys())
|
|
|
|
def values(self):
|
|
|
|
return tuple(super().values())
|
|
|
|
def items(self):
|
|
|
|
return tuple(super().items())
|
|
|
|
dict_obj = {'foo': 1, 'bar': 2, 'spam': 3}
|
|
|
|
|
|
|
|
for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(),
|
|
|
|
dict_obj, OrderedDict(dict_obj),
|
|
|
|
Mapping1(dict_obj), Mapping2(dict_obj)]:
|
2024-03-19 07:44:13 -03:00
|
|
|
self.assertListEqual(_testlimitedcapi.mapping_keys(mapping),
|
2023-08-07 12:51:43 -03:00
|
|
|
list(mapping.keys()))
|
2024-03-19 07:44:13 -03:00
|
|
|
self.assertListEqual(_testlimitedcapi.mapping_values(mapping),
|
2023-08-07 12:51:43 -03:00
|
|
|
list(mapping.values()))
|
2024-03-19 07:44:13 -03:00
|
|
|
self.assertListEqual(_testlimitedcapi.mapping_items(mapping),
|
2023-08-07 12:51:43 -03:00
|
|
|
list(mapping.items()))
|
|
|
|
|
|
|
|
def test_mapping_keys_valuesitems_bad_arg(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_keys, object())
|
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_values, object())
|
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_items, object())
|
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_keys, [])
|
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_values, [])
|
|
|
|
self.assertRaises(AttributeError, _testlimitedcapi.mapping_items, [])
|
|
|
|
self.assertRaises(SystemError, _testlimitedcapi.mapping_keys, NULL)
|
|
|
|
self.assertRaises(SystemError, _testlimitedcapi.mapping_values, NULL)
|
|
|
|
self.assertRaises(SystemError, _testlimitedcapi.mapping_items, NULL)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
class BadMapping:
|
|
|
|
def keys(self):
|
|
|
|
return None
|
|
|
|
def values(self):
|
|
|
|
return None
|
|
|
|
def items(self):
|
|
|
|
return None
|
|
|
|
bad_mapping = BadMapping()
|
2024-03-19 07:44:13 -03:00
|
|
|
self.assertRaises(TypeError, _testlimitedcapi.mapping_keys, bad_mapping)
|
|
|
|
self.assertRaises(TypeError, _testlimitedcapi.mapping_values, bad_mapping)
|
|
|
|
self.assertRaises(TypeError, _testlimitedcapi.mapping_items, bad_mapping)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
def test_sequence_check(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
check = _testlimitedcapi.sequence_check
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertFalse(check({1: 2}))
|
|
|
|
self.assertTrue(check([1, 2]))
|
|
|
|
self.assertTrue(check((1, 2)))
|
|
|
|
self.assertTrue(check('abc'))
|
|
|
|
self.assertTrue(check(b'abc'))
|
|
|
|
self.assertFalse(check(42))
|
|
|
|
self.assertFalse(check(object()))
|
|
|
|
# CRASHES check(NULL)
|
|
|
|
|
|
|
|
def test_sequence_size(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
for size in _testlimitedcapi.sequence_size, _testlimitedcapi.sequence_length:
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(size([1, 2]), 2)
|
|
|
|
self.assertEqual(size((1, 2)), 2)
|
|
|
|
self.assertEqual(size('abc'), 3)
|
|
|
|
self.assertEqual(size(b'abc'), 3)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, size, {})
|
|
|
|
self.assertRaises(TypeError, size, 42)
|
|
|
|
self.assertRaises(TypeError, size, object())
|
|
|
|
self.assertRaises(SystemError, size, NULL)
|
|
|
|
|
|
|
|
def test_sequence_getitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
getitem = _testlimitedcapi.sequence_getitem
|
2023-08-07 12:51:43 -03:00
|
|
|
lst = ['a', 'b', 'c']
|
|
|
|
self.assertEqual(getitem(lst, 1), 'b')
|
|
|
|
self.assertEqual(getitem(lst, -1), 'c')
|
|
|
|
self.assertRaises(IndexError, getitem, lst, 3)
|
2023-11-04 06:40:46 -03:00
|
|
|
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
|
|
|
|
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
self.assertRaises(TypeError, getitem, 42, 1)
|
|
|
|
self.assertRaises(TypeError, getitem, {}, 1)
|
|
|
|
self.assertRaises(SystemError, getitem, NULL, 1)
|
|
|
|
|
|
|
|
def test_sequence_concat(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
concat = _testlimitedcapi.sequence_concat
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(concat(['a', 'b'], [1, 2]), ['a', 'b', 1, 2])
|
|
|
|
self.assertEqual(concat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2))
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, concat, [], ())
|
|
|
|
self.assertRaises(TypeError, concat, (), [])
|
|
|
|
self.assertRaises(TypeError, concat, [], 42)
|
|
|
|
self.assertRaises(TypeError, concat, 42, [])
|
|
|
|
self.assertRaises(TypeError, concat, 42, 43)
|
|
|
|
self.assertRaises(SystemError, concat, [], NULL)
|
|
|
|
self.assertRaises(SystemError, concat, NULL, [])
|
|
|
|
|
|
|
|
def test_sequence_repeat(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
repeat = _testlimitedcapi.sequence_repeat
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(repeat(['a', 'b'], 2), ['a', 'b', 'a', 'b'])
|
|
|
|
self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
|
|
|
|
self.assertEqual(repeat(['a', 'b'], 0), [])
|
|
|
|
self.assertEqual(repeat(['a', 'b'], -1), [])
|
2023-11-04 06:40:46 -03:00
|
|
|
self.assertEqual(repeat(['a', 'b'], PY_SSIZE_T_MIN), [])
|
|
|
|
self.assertEqual(repeat([], PY_SSIZE_T_MAX), [])
|
|
|
|
self.assertRaises(MemoryError, repeat, ['a', 'b'], PY_SSIZE_T_MAX)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
self.assertRaises(TypeError, repeat, set(), 2)
|
|
|
|
self.assertRaises(TypeError, repeat, 42, 2)
|
|
|
|
self.assertRaises(SystemError, repeat, NULL, 2)
|
|
|
|
|
|
|
|
def test_sequence_inplaceconcat(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
inplaceconcat = _testlimitedcapi.sequence_inplaceconcat
|
2023-08-07 12:51:43 -03:00
|
|
|
lst = ['a', 'b']
|
|
|
|
res = inplaceconcat(lst, [1, 2])
|
|
|
|
self.assertEqual(res, ['a', 'b', 1, 2])
|
|
|
|
self.assertIs(res, lst)
|
|
|
|
lst = ['a', 'b']
|
|
|
|
res = inplaceconcat(lst, (1, 2))
|
|
|
|
self.assertEqual(res, ['a', 'b', 1, 2])
|
|
|
|
self.assertIs(res, lst)
|
|
|
|
self.assertEqual(inplaceconcat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2))
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, inplaceconcat, (), [])
|
|
|
|
self.assertRaises(TypeError, inplaceconcat, [], 42)
|
|
|
|
self.assertRaises(TypeError, inplaceconcat, 42, [])
|
|
|
|
self.assertRaises(TypeError, inplaceconcat, 42, 43)
|
|
|
|
self.assertRaises(SystemError, inplaceconcat, [], NULL)
|
|
|
|
self.assertRaises(SystemError, inplaceconcat, NULL, [])
|
|
|
|
|
|
|
|
def test_sequence_inplacerepeat(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
inplacerepeat = _testlimitedcapi.sequence_inplacerepeat
|
2023-08-07 12:51:43 -03:00
|
|
|
lst = ['a', 'b']
|
|
|
|
res = inplacerepeat(lst, 2)
|
|
|
|
self.assertEqual(res, ['a', 'b', 'a', 'b'])
|
|
|
|
self.assertIs(res, lst)
|
|
|
|
self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
|
|
|
|
self.assertEqual(inplacerepeat(['a', 'b'], 0), [])
|
|
|
|
self.assertEqual(inplacerepeat(['a', 'b'], -1), [])
|
2023-11-04 06:40:46 -03:00
|
|
|
self.assertEqual(inplacerepeat(['a', 'b'], PY_SSIZE_T_MIN), [])
|
|
|
|
self.assertEqual(inplacerepeat([], PY_SSIZE_T_MAX), [])
|
|
|
|
self.assertRaises(MemoryError, inplacerepeat, ['a', 'b'], PY_SSIZE_T_MAX)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
self.assertRaises(TypeError, inplacerepeat, set(), 2)
|
|
|
|
self.assertRaises(TypeError, inplacerepeat, 42, 2)
|
|
|
|
self.assertRaises(SystemError, inplacerepeat, NULL, 2)
|
|
|
|
|
|
|
|
def test_sequence_setitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
setitem = _testlimitedcapi.sequence_setitem
|
2023-08-07 12:51:43 -03:00
|
|
|
lst = ['a', 'b', 'c']
|
|
|
|
setitem(lst, 1, 'x')
|
|
|
|
self.assertEqual(lst, ['a', 'x', 'c'])
|
|
|
|
setitem(lst, -1, 'y')
|
|
|
|
self.assertEqual(lst, ['a', 'x', 'y'])
|
|
|
|
|
|
|
|
setitem(lst, 0, NULL)
|
|
|
|
self.assertEqual(lst, ['x', 'y'])
|
|
|
|
self.assertRaises(IndexError, setitem, lst, 3, 'x')
|
2023-11-04 06:40:46 -03:00
|
|
|
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 'x')
|
|
|
|
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 'x')
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
self.assertRaises(TypeError, setitem, 42, 1, 'x')
|
|
|
|
self.assertRaises(TypeError, setitem, {}, 1, 'x')
|
|
|
|
self.assertRaises(SystemError, setitem, NULL, 1, 'x')
|
|
|
|
|
|
|
|
def test_sequence_delitem(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
delitem = _testlimitedcapi.sequence_delitem
|
2023-08-07 12:51:43 -03:00
|
|
|
lst = ['a', 'b', 'c']
|
|
|
|
delitem(lst, 1)
|
|
|
|
self.assertEqual(lst, ['a', 'c'])
|
|
|
|
delitem(lst, -1)
|
|
|
|
self.assertEqual(lst, ['a'])
|
|
|
|
self.assertRaises(IndexError, delitem, lst, 3)
|
2023-11-04 06:40:46 -03:00
|
|
|
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MAX)
|
|
|
|
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MIN)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
self.assertRaises(TypeError, delitem, 42, 1)
|
|
|
|
self.assertRaises(TypeError, delitem, {}, 1)
|
|
|
|
self.assertRaises(SystemError, delitem, NULL, 1)
|
|
|
|
|
|
|
|
def test_sequence_setslice(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
setslice = _testlimitedcapi.sequence_setslice
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
# Correct case:
|
2023-11-04 06:40:46 -03:00
|
|
|
for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
|
|
|
|
for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
|
|
|
|
data = [1, 2, 3, 4, 5]
|
|
|
|
data_copy = [1, 2, 3, 4, 5]
|
|
|
|
setslice(data, start, stop, [8, 9])
|
|
|
|
data_copy[start:stop] = [8, 9]
|
|
|
|
self.assertEqual(data, data_copy)
|
|
|
|
|
|
|
|
data = [1, 2, 3, 4, 5]
|
|
|
|
data_copy = [1, 2, 3, 4, 5]
|
|
|
|
setslice(data, start, stop, NULL)
|
|
|
|
del data_copy[start:stop]
|
|
|
|
self.assertEqual(data, data_copy)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
# Custom class:
|
|
|
|
class Custom:
|
|
|
|
def __setitem__(self, index, value):
|
|
|
|
self.index = index
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
c = Custom()
|
|
|
|
setslice(c, 0, 5, 'abc')
|
|
|
|
self.assertEqual(c.index, slice(0, 5))
|
|
|
|
self.assertEqual(c.value, 'abc')
|
|
|
|
|
|
|
|
# Immutable sequences must raise:
|
|
|
|
bad_seq1 = (1, 2, 3, 4)
|
|
|
|
self.assertRaises(TypeError, setslice, bad_seq1, 1, 3, (8, 9))
|
|
|
|
self.assertEqual(bad_seq1, (1, 2, 3, 4))
|
|
|
|
|
|
|
|
bad_seq2 = 'abcd'
|
|
|
|
self.assertRaises(TypeError, setslice, bad_seq2, 1, 3, 'xy')
|
|
|
|
self.assertEqual(bad_seq2, 'abcd')
|
|
|
|
|
|
|
|
# Not a sequence:
|
|
|
|
self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy')
|
|
|
|
self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy')
|
|
|
|
|
|
|
|
def test_sequence_delslice(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
delslice = _testlimitedcapi.sequence_delslice
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
# Correct case:
|
2023-11-04 06:40:46 -03:00
|
|
|
for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
|
|
|
|
for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
|
|
|
|
data = [1, 2, 3, 4, 5]
|
|
|
|
data_copy = [1, 2, 3, 4, 5]
|
|
|
|
delslice(data, start, stop)
|
|
|
|
del data_copy[start:stop]
|
|
|
|
self.assertEqual(data, data_copy)
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
# Custom class:
|
|
|
|
class Custom:
|
|
|
|
def __delitem__(self, index):
|
|
|
|
self.index = index
|
|
|
|
|
|
|
|
c = Custom()
|
|
|
|
delslice(c, 0, 5)
|
|
|
|
self.assertEqual(c.index, slice(0, 5))
|
|
|
|
|
|
|
|
# Immutable sequences must raise:
|
|
|
|
bad_seq1 = (1, 2, 3, 4)
|
|
|
|
self.assertRaises(TypeError, delslice, bad_seq1, 1, 3)
|
|
|
|
self.assertEqual(bad_seq1, (1, 2, 3, 4))
|
|
|
|
|
|
|
|
bad_seq2 = 'abcd'
|
|
|
|
self.assertRaises(TypeError, delslice, bad_seq2, 1, 3)
|
|
|
|
self.assertEqual(bad_seq2, 'abcd')
|
|
|
|
|
|
|
|
# Not a sequence:
|
|
|
|
self.assertRaises(TypeError, delslice, object(), 1, 3)
|
|
|
|
self.assertRaises(SystemError, delslice, NULL, 1, 3)
|
|
|
|
|
|
|
|
mapping = {1: 'a', 2: 'b', 3: 'c'}
|
|
|
|
self.assertRaises(KeyError, delslice, mapping, 1, 3)
|
|
|
|
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
|
|
|
|
|
|
|
|
def test_sequence_count(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
count = _testlimitedcapi.sequence_count
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
lst = ['a', 'b', 'a']
|
|
|
|
self.assertEqual(count(lst, 'a'), 2)
|
|
|
|
self.assertEqual(count(lst, 'c'), 0)
|
|
|
|
self.assertEqual(count(iter(lst), 'a'), 2)
|
|
|
|
self.assertEqual(count(iter(lst), 'c'), 0)
|
|
|
|
self.assertEqual(count({'a': 2}, 'a'), 1)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, count, 42, 'a')
|
|
|
|
self.assertRaises(SystemError, count, [], NULL)
|
|
|
|
self.assertRaises(SystemError, count, [1], NULL)
|
|
|
|
self.assertRaises(SystemError, count, NULL, 'a')
|
|
|
|
|
|
|
|
def test_sequence_contains(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
contains = _testlimitedcapi.sequence_contains
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
lst = ['a', 'b', 'a']
|
|
|
|
self.assertEqual(contains(lst, 'a'), 1)
|
|
|
|
self.assertEqual(contains(lst, 'c'), 0)
|
|
|
|
self.assertEqual(contains(iter(lst), 'a'), 1)
|
|
|
|
self.assertEqual(contains(iter(lst), 'c'), 0)
|
|
|
|
self.assertEqual(contains({'a': 2}, 'a'), 1)
|
|
|
|
|
|
|
|
# XXX Only for empty sequences. Should be SystemError?
|
|
|
|
self.assertEqual(contains([], NULL), 0)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, contains, 42, 'a')
|
|
|
|
self.assertRaises(SystemError, contains, [1], NULL)
|
|
|
|
# CRASHES contains({}, NULL)
|
|
|
|
# CRASHES contains(set(), NULL)
|
|
|
|
# CRASHES contains(NULL, 'a')
|
|
|
|
|
|
|
|
def test_sequence_index(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
index = _testlimitedcapi.sequence_index
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
lst = ['a', 'b', 'a']
|
|
|
|
self.assertEqual(index(lst, 'a'), 0)
|
|
|
|
self.assertEqual(index(lst, 'b'), 1)
|
|
|
|
self.assertRaises(ValueError, index, lst, 'c')
|
|
|
|
self.assertEqual(index(iter(lst), 'a'), 0)
|
|
|
|
self.assertEqual(index(iter(lst), 'b'), 1)
|
|
|
|
self.assertRaises(ValueError, index, iter(lst), 'c')
|
|
|
|
dct = {'a': 2, 'b': 3}
|
|
|
|
self.assertEqual(index(dct, 'a'), 0)
|
|
|
|
self.assertEqual(index(dct, 'b'), 1)
|
|
|
|
self.assertRaises(ValueError, index, dct, 'c')
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, index, 42, 'a')
|
|
|
|
self.assertRaises(SystemError, index, [], NULL)
|
|
|
|
self.assertRaises(SystemError, index, [1], NULL)
|
|
|
|
self.assertRaises(SystemError, index, NULL, 'a')
|
|
|
|
|
|
|
|
def test_sequence_list(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xlist = _testlimitedcapi.sequence_list
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(xlist(['a', 'b', 'c']), ['a', 'b', 'c'])
|
|
|
|
self.assertEqual(xlist(('a', 'b', 'c')), ['a', 'b', 'c'])
|
|
|
|
self.assertEqual(xlist(iter(['a', 'b', 'c'])), ['a', 'b', 'c'])
|
|
|
|
self.assertEqual(xlist(gen()), ['a', 'b', 'c'])
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, xlist, 42)
|
|
|
|
self.assertRaises(SystemError, xlist, NULL)
|
|
|
|
|
|
|
|
def test_sequence_tuple(self):
|
2024-03-19 07:44:13 -03:00
|
|
|
xtuple = _testlimitedcapi.sequence_tuple
|
2023-08-07 12:51:43 -03:00
|
|
|
self.assertEqual(xtuple(['a', 'b', 'c']), ('a', 'b', 'c'))
|
|
|
|
self.assertEqual(xtuple(('a', 'b', 'c')), ('a', 'b', 'c'))
|
|
|
|
self.assertEqual(xtuple(iter(['a', 'b', 'c'])), ('a', 'b', 'c'))
|
|
|
|
self.assertEqual(xtuple(gen()), ('a', 'b', 'c'))
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, xtuple, 42)
|
|
|
|
self.assertRaises(SystemError, xtuple, NULL)
|
|
|
|
|
2024-03-22 15:19:10 -03:00
|
|
|
def test_object_generichash(self):
|
|
|
|
# Test PyObject_GenericHash()
|
|
|
|
generichash = _testcapi.object_generichash
|
|
|
|
for obj in object(), 1, 'string', []:
|
|
|
|
self.assertEqual(generichash(obj), object.__hash__(obj))
|
|
|
|
|
2024-08-07 19:47:15 -03:00
|
|
|
def run_iter_api_test(self, next_func):
|
|
|
|
for data in (), [], (1, 2, 3), [1 , 2, 3], "123":
|
|
|
|
with self.subTest(data=data):
|
|
|
|
items = []
|
|
|
|
it = iter(data)
|
|
|
|
while (item := next_func(it)) is not None:
|
|
|
|
items.append(item)
|
|
|
|
self.assertEqual(items, list(data))
|
|
|
|
|
|
|
|
class Broken:
|
|
|
|
def __init__(self):
|
|
|
|
self.count = 0
|
|
|
|
|
|
|
|
def __next__(self):
|
|
|
|
if self.count < 3:
|
|
|
|
self.count += 1
|
|
|
|
return self.count
|
|
|
|
else:
|
|
|
|
raise TypeError('bad type')
|
|
|
|
|
|
|
|
it = Broken()
|
|
|
|
self.assertEqual(next_func(it), 1)
|
|
|
|
self.assertEqual(next_func(it), 2)
|
|
|
|
self.assertEqual(next_func(it), 3)
|
|
|
|
with self.assertRaisesRegex(TypeError, 'bad type'):
|
|
|
|
next_func(it)
|
|
|
|
|
|
|
|
def test_iter_next(self):
|
|
|
|
from _testcapi import PyIter_Next
|
|
|
|
self.run_iter_api_test(PyIter_Next)
|
|
|
|
# CRASHES PyIter_Next(10)
|
|
|
|
|
|
|
|
def test_iter_nextitem(self):
|
|
|
|
from _testcapi import PyIter_NextItem
|
|
|
|
self.run_iter_api_test(PyIter_NextItem)
|
|
|
|
|
|
|
|
regex = "expected.*iterator.*got.*'int'"
|
|
|
|
with self.assertRaisesRegex(TypeError, regex):
|
|
|
|
PyIter_NextItem(10)
|
|
|
|
|
2023-08-07 12:51:43 -03:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|