Skip to content

[3.12] gh-111495: Add tests for PyBytes and PyByteArray C API (GH-111496) #111607

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

Merged
merged 1 commit into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions Lib/test/test_capi/test_bytearray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import unittest
import sys
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

NULL = None

class ByteArraySubclass(bytearray):
pass

class BytesLike:
def __init__(self, value):
self.value = value
def __bytes__(self):
return self.value


class CAPITest(unittest.TestCase):
def test_check(self):
# Test PyByteArray_Check()
check = _testcapi.bytearray_check
self.assertTrue(check(bytearray(b'abc')))
self.assertFalse(check(b'abc'))
self.assertTrue(check(ByteArraySubclass(b'abc')))
self.assertFalse(check(BytesLike(b'abc')))
self.assertFalse(check(3))
self.assertFalse(check([]))
self.assertFalse(check(object()))

# CRASHES check(NULL)

def test_checkexact(self):
# Test PyByteArray_CheckExact()
check = _testcapi.bytearray_checkexact
self.assertTrue(check(bytearray(b'abc')))
self.assertFalse(check(b'abc'))
self.assertFalse(check(ByteArraySubclass(b'abc')))
self.assertFalse(check(BytesLike(b'abc')))
self.assertFalse(check(3))
self.assertFalse(check([]))
self.assertFalse(check(object()))

# CRASHES check(NULL)

def test_fromstringandsize(self):
# Test PyByteArray_FromStringAndSize()
fromstringandsize = _testcapi.bytearray_fromstringandsize

self.assertEqual(fromstringandsize(b'abc'), bytearray(b'abc'))
self.assertEqual(fromstringandsize(b'abc', 2), bytearray(b'ab'))
self.assertEqual(fromstringandsize(b'abc\0def'), bytearray(b'abc\0def'))
self.assertEqual(fromstringandsize(b'', 0), bytearray())
self.assertEqual(fromstringandsize(NULL, 0), bytearray())
self.assertEqual(len(fromstringandsize(NULL, 3)), 3)
self.assertRaises(MemoryError, fromstringandsize, NULL, sys.maxsize)

self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)

def test_fromobject(self):
# Test PyByteArray_FromObject()
fromobject = _testcapi.bytearray_fromobject

self.assertEqual(fromobject(b'abc'), bytearray(b'abc'))
self.assertEqual(fromobject(bytearray(b'abc')), bytearray(b'abc'))
self.assertEqual(fromobject(ByteArraySubclass(b'abc')), bytearray(b'abc'))
self.assertEqual(fromobject([97, 98, 99]), bytearray(b'abc'))
self.assertEqual(fromobject(3), bytearray(b'\0\0\0'))
self.assertRaises(TypeError, fromobject, BytesLike(b'abc'))
self.assertRaises(TypeError, fromobject, 'abc')
self.assertRaises(TypeError, fromobject, object())

# CRASHES fromobject(NULL)

def test_size(self):
# Test PyByteArray_Size()
size = _testcapi.bytearray_size

self.assertEqual(size(bytearray(b'abc')), 3)
self.assertEqual(size(ByteArraySubclass(b'abc')), 3)

# CRASHES size(b'abc')
# CRASHES size(object())
# CRASHES size(NULL)

def test_asstring(self):
"""Test PyByteArray_AsString()"""
asstring = _testcapi.bytearray_asstring

self.assertEqual(asstring(bytearray(b'abc'), 4), b'abc\0')
self.assertEqual(asstring(ByteArraySubclass(b'abc'), 4), b'abc\0')
self.assertEqual(asstring(bytearray(b'abc\0def'), 8), b'abc\0def\0')

# CRASHES asstring(b'abc', 0)
# CRASHES asstring(object()', 0)
# CRASHES asstring(NULL, 0)

def test_concat(self):
"""Test PyByteArray_Concat()"""
concat = _testcapi.bytearray_concat

ba = bytearray(b'abc')
self.assertEqual(concat(ba, b'def'), bytearray(b'abcdef'))
self.assertEqual(ba, b'abc')

self.assertEqual(concat(b'abc', b'def'), bytearray(b'abcdef'))
self.assertEqual(concat(b'a\0b', b'c\0d'), bytearray(b'a\0bc\0d'))
self.assertEqual(concat(bytearray(b'abc'), b'def'), bytearray(b'abcdef'))
self.assertEqual(concat(b'abc', bytearray(b'def')), bytearray(b'abcdef'))
self.assertEqual(concat(bytearray(b'abc'), b''), bytearray(b'abc'))
self.assertEqual(concat(b'', bytearray(b'def')), bytearray(b'def'))
self.assertEqual(concat(memoryview(b'xabcy')[1:4], b'def'),
bytearray(b'abcdef'))
self.assertEqual(concat(b'abc', memoryview(b'xdefy')[1:4]),
bytearray(b'abcdef'))

self.assertRaises(TypeError, concat, memoryview(b'axbycz')[::2], b'def')
self.assertRaises(TypeError, concat, b'abc', memoryview(b'dxeyfz')[::2])
self.assertRaises(TypeError, concat, b'abc', 'def')
self.assertRaises(TypeError, concat, 'abc', b'def')
self.assertRaises(TypeError, concat, 'abc', 'def')
self.assertRaises(TypeError, concat, [], b'def')
self.assertRaises(TypeError, concat, b'abc', [])
self.assertRaises(TypeError, concat, [], [])

# CRASHES concat(NULL, bytearray(b'def'))
# CRASHES concat(bytearray(b'abc'), NULL)
# CRASHES concat(NULL, object())
# CRASHES concat(object(), NULL)

def test_resize(self):
"""Test PyByteArray_Resize()"""
resize = _testcapi.bytearray_resize

ba = bytearray(b'abcdef')
self.assertEqual(resize(ba, 3), 0)
self.assertEqual(ba, bytearray(b'abc'))
self.assertEqual(resize(ba, 10), 0)
self.assertEqual(len(ba), 10)
self.assertEqual(ba[:3], bytearray(b'abc'))
self.assertEqual(resize(ba, 2**20), 0)
self.assertEqual(len(ba), 2**20)
self.assertEqual(ba[:3], bytearray(b'abc'))
self.assertEqual(resize(ba, 0), 0)
self.assertEqual(ba, bytearray())

ba = ByteArraySubclass(b'abcdef')
self.assertEqual(resize(ba, 3), 0)
self.assertEqual(ba, bytearray(b'abc'))

self.assertRaises(MemoryError, resize, bytearray(), sys.maxsize)
self.assertRaises(MemoryError, resize, bytearray(1000), sys.maxsize)

# CRASHES resize(bytearray(b'abc'), -1)
# CRASHES resize(b'abc', 0)
# CRASHES resize(object(), 0)
# CRASHES resize(NULL, 0)


if __name__ == "__main__":
unittest.main()
216 changes: 216 additions & 0 deletions Lib/test/test_capi/test_bytes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import unittest
import sys
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

NULL = None

class BytesSubclass(bytes):
pass

class BytesLike:
def __init__(self, value):
self.value = value
def __bytes__(self):
return self.value


class CAPITest(unittest.TestCase):
def test_check(self):
# Test PyBytes_Check()
check = _testcapi.bytes_check
self.assertTrue(check(b'abc'))
self.assertFalse(check('abc'))
self.assertFalse(check(bytearray(b'abc')))
self.assertTrue(check(BytesSubclass(b'abc')))
self.assertFalse(check(BytesLike(b'abc')))
self.assertFalse(check(3))
self.assertFalse(check([]))
self.assertFalse(check(object()))

# CRASHES check(NULL)

def test_checkexact(self):
# Test PyBytes_CheckExact()
check = _testcapi.bytes_checkexact
self.assertTrue(check(b'abc'))
self.assertFalse(check('abc'))
self.assertFalse(check(bytearray(b'abc')))
self.assertFalse(check(BytesSubclass(b'abc')))
self.assertFalse(check(BytesLike(b'abc')))
self.assertFalse(check(3))
self.assertFalse(check([]))
self.assertFalse(check(object()))

# CRASHES check(NULL)

def test_fromstringandsize(self):
# Test PyBytes_FromStringAndSize()
fromstringandsize = _testcapi.bytes_fromstringandsize

self.assertEqual(fromstringandsize(b'abc'), b'abc')
self.assertEqual(fromstringandsize(b'abc', 2), b'ab')
self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def')
self.assertEqual(fromstringandsize(b'', 0), b'')
self.assertEqual(fromstringandsize(NULL, 0), b'')
self.assertEqual(len(fromstringandsize(NULL, 3)), 3)
self.assertRaises((MemoryError, OverflowError), fromstringandsize, NULL, sys.maxsize)

self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)

def test_fromstring(self):
# Test PyBytes_FromString()
fromstring = _testcapi.bytes_fromstring

self.assertEqual(fromstring(b'abc\0def'), b'abc')
self.assertEqual(fromstring(b''), b'')

# CRASHES fromstring(NULL)

def test_fromobject(self):
# Test PyBytes_FromObject()
fromobject = _testcapi.bytes_fromobject

self.assertEqual(fromobject(b'abc'), b'abc')
self.assertEqual(fromobject(bytearray(b'abc')), b'abc')
self.assertEqual(fromobject(BytesSubclass(b'abc')), b'abc')
self.assertEqual(fromobject([97, 98, 99]), b'abc')
self.assertRaises(TypeError, fromobject, 3)
self.assertRaises(TypeError, fromobject, BytesLike(b'abc'))
self.assertRaises(TypeError, fromobject, 'abc')
self.assertRaises(TypeError, fromobject, object())
self.assertRaises(SystemError, fromobject, NULL)

def test_size(self):
# Test PyBytes_Size()
size = _testcapi.bytes_size

self.assertEqual(size(b'abc'), 3)
self.assertEqual(size(BytesSubclass(b'abc')), 3)
self.assertRaises(TypeError, size, bytearray(b'abc'))
self.assertRaises(TypeError, size, 'abc')
self.assertRaises(TypeError, size, object())

# CRASHES size(NULL)

def test_asstring(self):
"""Test PyBytes_AsString()"""
asstring = _testcapi.bytes_asstring

self.assertEqual(asstring(b'abc', 4), b'abc\0')
self.assertEqual(asstring(b'abc\0def', 8), b'abc\0def\0')
self.assertRaises(TypeError, asstring, 'abc', 0)
self.assertRaises(TypeError, asstring, object(), 0)

# CRASHES asstring(NULL, 0)

def test_asstringandsize(self):
"""Test PyBytes_AsStringAndSize()"""
asstringandsize = _testcapi.bytes_asstringandsize
asstringandsize_null = _testcapi.bytes_asstringandsize_null

self.assertEqual(asstringandsize(b'abc', 4), (b'abc\0', 3))
self.assertEqual(asstringandsize(b'abc\0def', 8), (b'abc\0def\0', 7))
self.assertEqual(asstringandsize_null(b'abc', 4), b'abc\0')
self.assertRaises(ValueError, asstringandsize_null, b'abc\0def', 8)
self.assertRaises(TypeError, asstringandsize, 'abc', 0)
self.assertRaises(TypeError, asstringandsize_null, 'abc', 0)
self.assertRaises(TypeError, asstringandsize, object(), 0)
self.assertRaises(TypeError, asstringandsize_null, object(), 0)

# CRASHES asstringandsize(NULL, 0)
# CRASHES asstringandsize_null(NULL, 0)

def test_repr(self):
# Test PyBytes_Repr()
bytes_repr = _testcapi.bytes_repr

self.assertEqual(bytes_repr(b'''abc''', 0), r"""b'abc'""")
self.assertEqual(bytes_repr(b'''abc''', 1), r"""b'abc'""")
self.assertEqual(bytes_repr(b'''a'b"c"d''', 0), r"""b'a\'b"c"d'""")
self.assertEqual(bytes_repr(b'''a'b"c"d''', 1), r"""b'a\'b"c"d'""")
self.assertEqual(bytes_repr(b'''a'b"c''', 0), r"""b'a\'b"c'""")
self.assertEqual(bytes_repr(b'''a'b"c''', 1), r"""b'a\'b"c'""")
self.assertEqual(bytes_repr(b'''a'b'c"d''', 0), r"""b'a\'b\'c"d'""")
self.assertEqual(bytes_repr(b'''a'b'c"d''', 1), r"""b'a\'b\'c"d'""")
self.assertEqual(bytes_repr(b'''a'b'c'd''', 0), r"""b'a\'b\'c\'d'""")
self.assertEqual(bytes_repr(b'''a'b'c'd''', 1), r'''b"a'b'c'd"''')

self.assertEqual(bytes_repr(BytesSubclass(b'abc'), 0), r"""b'abc'""")

# UDEFINED bytes_repr(object(), 0)
# CRASHES bytes_repr(NULL, 0)

def test_concat(self, concat=None):
"""Test PyBytes_Concat()"""
if concat is None:
concat = _testcapi.bytes_concat

self.assertEqual(concat(b'abc', b'def'), b'abcdef')
self.assertEqual(concat(b'a\0b', b'c\0d'), b'a\0bc\0d')
self.assertEqual(concat(bytearray(b'abc'), b'def'), b'abcdef')
self.assertEqual(concat(b'abc', bytearray(b'def')), b'abcdef')
self.assertEqual(concat(bytearray(b'abc'), b''), b'abc')
self.assertEqual(concat(b'', bytearray(b'def')), b'def')
self.assertEqual(concat(memoryview(b'xabcy')[1:4], b'def'), b'abcdef')
self.assertEqual(concat(b'abc', memoryview(b'xdefy')[1:4]), b'abcdef')

self.assertEqual(concat(b'abc', b'def', True), b'abcdef')
self.assertEqual(concat(b'abc', bytearray(b'def'), True), b'abcdef')
# Check that it does not change the singleton
self.assertEqual(concat(bytes(), b'def', True), b'def')
self.assertEqual(len(bytes()), 0)

self.assertRaises(TypeError, concat, memoryview(b'axbycz')[::2], b'def')
self.assertRaises(TypeError, concat, b'abc', memoryview(b'dxeyfz')[::2])
self.assertRaises(TypeError, concat, b'abc', 'def')
self.assertRaises(TypeError, concat, 'abc', b'def')
self.assertRaises(TypeError, concat, 'abc', 'def')
self.assertRaises(TypeError, concat, [], b'def')
self.assertRaises(TypeError, concat, b'abc', [])
self.assertRaises(TypeError, concat, [], [])

self.assertEqual(concat(NULL, b'def'), NULL)
self.assertEqual(concat(b'abc', NULL), NULL)
self.assertEqual(concat(NULL, object()), NULL)
self.assertEqual(concat(object(), NULL), NULL)

def test_concatanddel(self):
"""Test PyBytes_ConcatAndDel()"""
self.test_concat(_testcapi.bytes_concatanddel)

def test_decodeescape(self):
"""Test PyBytes_DecodeEscape()"""
decodeescape = _testcapi.bytes_decodeescape

self.assertEqual(decodeescape(b'abc'), b'abc')
self.assertEqual(decodeescape(br'\t\n\r\x0b\x0c\x00\\\'\"'),
b'''\t\n\r\v\f\0\\'"''')
self.assertEqual(decodeescape(b'\t\n\r\x0b\x0c\x00'), b'\t\n\r\v\f\0')
self.assertEqual(decodeescape(br'\xa1\xa2'), b'\xa1\xa2')
self.assertEqual(decodeescape(br'\2\24\241'), b'\x02\x14\xa1')
self.assertEqual(decodeescape(b'\xa1\xa2'), b'\xa1\xa2')
with self.assertWarns(DeprecationWarning):
self.assertEqual(decodeescape(br'\u4f60'), br'\u4f60')
with self.assertWarns(DeprecationWarning):
self.assertEqual(decodeescape(br'\z'), br'\z')
with self.assertWarns(DeprecationWarning):
self.assertEqual(decodeescape(br'\541'), b'a')

for b in b'\\', br'\x', br'\xa', br'\xz', br'\xaz':
self.assertRaises(ValueError, decodeescape, b)
self.assertRaises(ValueError, decodeescape, b, 'strict')
self.assertEqual(decodeescape(br'x\xa', 'replace'), b'x?')
self.assertEqual(decodeescape(br'x\xay', 'replace'), b'x?y')
self.assertEqual(decodeescape(br'x\xa\xy', 'replace'), b'x??y')
self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy')
self.assertRaises(ValueError, decodeescape, b'\\', 'spam')
self.assertEqual(decodeescape(NULL), b'')

# CRASHES decodeescape(NULL, NULL, 1)


if __name__ == "__main__":
unittest.main()
4 changes: 3 additions & 1 deletion Lib/test/test_capi/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ def test_fromstringandsize(self):
self.assertEqual(fromstringandsize(NULL, 0), '')

self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
# TODO: Test PyUnicode_FromStringAndSize(NULL, size) for size != 0
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, 3)
self.assertRaises(SystemError, fromstringandsize, NULL, sys.maxsize)

@support.cpython_only
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
Expand Down
Loading