gh-111495: Test C API functions with extreme sizes and indices (GH-111631)

This commit is contained in:
Serhiy Storchaka 2023-11-04 11:40:46 +02:00 committed by GitHub
parent f48e669504
commit a8e1f474c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 39 deletions

View File

@ -1,7 +1,9 @@
import unittest
from collections import OrderedDict
import _testcapi
from test.support import import_helper
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
NULL = None
@ -574,6 +576,8 @@ class CAPITest(unittest.TestCase):
self.assertEqual(getitem(lst, 1), 'b')
self.assertEqual(getitem(lst, -1), 'c')
self.assertRaises(IndexError, getitem, lst, 3)
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN)
self.assertRaises(TypeError, getitem, 42, 1)
self.assertRaises(TypeError, getitem, {}, 1)
@ -598,6 +602,9 @@ class CAPITest(unittest.TestCase):
self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(repeat(['a', 'b'], 0), [])
self.assertEqual(repeat(['a', 'b'], -1), [])
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)
self.assertRaises(TypeError, repeat, set(), 2)
self.assertRaises(TypeError, repeat, 42, 2)
@ -631,6 +638,9 @@ class CAPITest(unittest.TestCase):
self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(inplacerepeat(['a', 'b'], 0), [])
self.assertEqual(inplacerepeat(['a', 'b'], -1), [])
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)
self.assertRaises(TypeError, inplacerepeat, set(), 2)
self.assertRaises(TypeError, inplacerepeat, 42, 2)
@ -647,6 +657,8 @@ class CAPITest(unittest.TestCase):
setitem(lst, 0, NULL)
self.assertEqual(lst, ['x', 'y'])
self.assertRaises(IndexError, setitem, lst, 3, 'x')
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 'x')
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 'x')
self.assertRaises(TypeError, setitem, 42, 1, 'x')
self.assertRaises(TypeError, setitem, {}, 1, 'x')
@ -660,6 +672,8 @@ class CAPITest(unittest.TestCase):
delitem(lst, -1)
self.assertEqual(lst, ['a'])
self.assertRaises(IndexError, delitem, lst, 3)
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MAX)
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MIN)
self.assertRaises(TypeError, delitem, 42, 1)
self.assertRaises(TypeError, delitem, {}, 1)
@ -669,13 +683,19 @@ class CAPITest(unittest.TestCase):
setslice = _testcapi.sequence_setslice
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
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)
setslice(data, 1, 3, [8, 9])
data_copy[1:3] = [8, 9]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 8, 9, 4, 5])
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)
# Custom class:
class Custom:
@ -701,21 +721,17 @@ class CAPITest(unittest.TestCase):
self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy')
self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy')
data_copy = data.copy()
setslice(data_copy, 1, 3, NULL)
self.assertEqual(data_copy, [1, 4, 5])
def test_sequence_delslice(self):
delslice = _testcapi.sequence_delslice
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
delslice(data, 1, 3)
del data_copy[1:3]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 4, 5])
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)
# Custom class:
class Custom:

View File

@ -1,8 +1,8 @@
import unittest
import sys
from test.support import import_helper
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
NULL = None
@ -53,10 +53,12 @@ class CAPITest(unittest.TestCase):
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(MemoryError, fromstringandsize, NULL, PY_SSIZE_T_MAX)
self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN)
def test_fromobject(self):
# Test PyByteArray_FromObject()
@ -149,8 +151,8 @@ class CAPITest(unittest.TestCase):
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)
self.assertRaises(MemoryError, resize, bytearray(), PY_SSIZE_T_MAX)
self.assertRaises(MemoryError, resize, bytearray(1000), PY_SSIZE_T_MAX)
# CRASHES resize(bytearray(b'abc'), -1)
# CRASHES resize(b'abc', 0)

View File

@ -1,8 +1,8 @@
import unittest
import sys
from test.support import import_helper
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
NULL = None
@ -55,10 +55,13 @@ class CAPITest(unittest.TestCase):
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((MemoryError, OverflowError),
fromstringandsize, NULL, PY_SSIZE_T_MAX)
self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN)
def test_fromstring(self):
# Test PyBytes_FromString()
@ -208,7 +211,10 @@ class CAPITest(unittest.TestCase):
self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy')
self.assertRaises(ValueError, decodeescape, b'\\', 'spam')
self.assertEqual(decodeescape(NULL), b'')
self.assertRaises(OverflowError, decodeescape, b'abc', NULL, PY_SSIZE_T_MAX)
self.assertRaises(OverflowError, decodeescape, NULL, NULL, PY_SSIZE_T_MAX)
# CRASHES decodeescape(b'abc', NULL, -1)
# CRASHES decodeescape(NULL, NULL, 1)

View File

@ -5,6 +5,7 @@ from test.support import import_helper
try:
import _testcapi
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX
except ImportError:
_testcapi = None
try:
@ -30,9 +31,17 @@ class CAPITest(unittest.TestCase):
for maxchar in 0, 0x61, 0xa1, 0x4f60, 0x1f600, 0x10ffff:
self.assertEqual(new(0, maxchar), '')
self.assertEqual(new(5, maxchar), chr(maxchar)*5)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX, maxchar)
self.assertEqual(new(0, 0x110000), '')
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x4f60)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x4f60)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x1f600)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x1f600)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4, 0x1f600)
self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4+1, 0x1f600)
self.assertRaises(SystemError, new, 5, 0x110000)
self.assertRaises(SystemError, new, -1, 0)
self.assertRaises(SystemError, new, PY_SSIZE_T_MIN, 0)
@support.cpython_only
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
@ -53,8 +62,8 @@ class CAPITest(unittest.TestCase):
for to in strings[:idx]:
self.assertRaises(ValueError, fill, to, 0, 0, fill_char)
for to in strings[idx:]:
for start in range(7):
for length in range(-1, 7 - start):
for start in [*range(7), PY_SSIZE_T_MAX]:
for length in [*range(-1, 7 - start), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
filled = max(min(length, 5 - start), 0)
if filled == 5 and to != strings[idx]:
# narrow -> wide
@ -66,6 +75,7 @@ class CAPITest(unittest.TestCase):
s = strings[0]
self.assertRaises(IndexError, fill, s, -1, 0, 0x78)
self.assertRaises(IndexError, fill, s, PY_SSIZE_T_MIN, 0, 0x78)
self.assertRaises(ValueError, fill, s, 0, 0, 0x110000)
self.assertRaises(SystemError, fill, b'abc', 0, 0, 0x78)
self.assertRaises(SystemError, fill, [], 0, 0, 0x78)
@ -76,7 +86,7 @@ class CAPITest(unittest.TestCase):
@support.cpython_only
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
def test_writechar(self):
"""Test PyUnicode_ReadChar()"""
"""Test PyUnicode_WriteChar()"""
from _testcapi import unicode_writechar as writechar
strings = [
@ -96,10 +106,12 @@ class CAPITest(unittest.TestCase):
self.assertRaises(IndexError, writechar, 'abc', 3, 0x78)
self.assertRaises(IndexError, writechar, 'abc', -1, 0x78)
self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MAX, 0x78)
self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MIN, 0x78)
self.assertRaises(TypeError, writechar, b'abc', 0, 0x78)
self.assertRaises(TypeError, writechar, [], 0, 0x78)
# CRASHES writechar(NULL, 0, 0x78)
# TODO: Test PyUnicode_CopyCharacters() with non-modifiable and legacy
# TODO: Test PyUnicode_WriteChar() with non-modifiable and legacy
# unicode.
@support.cpython_only
@ -117,7 +129,11 @@ class CAPITest(unittest.TestCase):
self.assertEqual(resize(s, 3), (s, 0))
self.assertEqual(resize(s, 2), (s[:2], 0))
self.assertEqual(resize(s, 4), (s + '\0', 0))
self.assertEqual(resize(s, 10), (s + '\0'*7, 0))
self.assertEqual(resize(s, 0), ('', 0))
self.assertRaises(MemoryError, resize, s, PY_SSIZE_T_MAX)
self.assertRaises(SystemError, resize, s, -1)
self.assertRaises(SystemError, resize, s, PY_SSIZE_T_MIN)
self.assertRaises(SystemError, resize, b'abc', 0)
self.assertRaises(SystemError, resize, [], 0)
self.assertRaises(SystemError, resize, NULL, 0)
@ -196,10 +212,13 @@ class CAPITest(unittest.TestCase):
self.assertEqual(fromstringandsize(b'', 0), '')
self.assertEqual(fromstringandsize(NULL, 0), '')
self.assertRaises(MemoryError, fromstringandsize, b'abc', PY_SSIZE_T_MAX)
self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, 3)
self.assertRaises(SystemError, fromstringandsize, NULL, sys.maxsize)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MAX)
@support.cpython_only
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
@ -247,7 +266,9 @@ class CAPITest(unittest.TestCase):
for kind in -1, 0, 3, 5, 8:
self.assertRaises(SystemError, fromkindanddata, kind, b'')
self.assertRaises(ValueError, fromkindanddata, 1, b'abc', -1)
self.assertRaises(ValueError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(ValueError, fromkindanddata, 1, NULL, -1)
self.assertRaises(ValueError, fromkindanddata, 1, NULL, PY_SSIZE_T_MIN)
# CRASHES fromkindanddata(1, NULL, 1)
# CRASHES fromkindanddata(4, b'\xff\xff\xff\xff')
@ -263,12 +284,14 @@ class CAPITest(unittest.TestCase):
'ab\xa1\xa2\u4f60\u597d\U0001f600\U0001f601'
]
for s in strings:
for start in range(0, len(s) + 2):
for end in range(max(start-1, 0), len(s) + 2):
for start in [*range(0, len(s) + 2), PY_SSIZE_T_MAX]:
for end in [*range(max(start-1, 0), len(s) + 2), PY_SSIZE_T_MAX]:
self.assertEqual(substring(s, start, end), s[start:end])
self.assertRaises(IndexError, substring, 'abc', -1, 0)
self.assertRaises(IndexError, substring, 'abc', PY_SSIZE_T_MIN, 0)
self.assertRaises(IndexError, substring, 'abc', 0, -1)
self.assertRaises(IndexError, substring, 'abc', 0, PY_SSIZE_T_MIN)
# CRASHES substring(b'abc', 0, 0)
# CRASHES substring([], 0, 0)
# CRASHES substring(NULL, 0, 0)
@ -298,7 +321,9 @@ class CAPITest(unittest.TestCase):
for i, c in enumerate(s):
self.assertEqual(readchar(s, i), ord(c))
self.assertRaises(IndexError, readchar, s, len(s))
self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MAX)
self.assertRaises(IndexError, readchar, s, -1)
self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MIN)
self.assertRaises(TypeError, readchar, b'abc', 0)
self.assertRaises(TypeError, readchar, [], 0)
@ -733,10 +758,15 @@ class CAPITest(unittest.TestCase):
if SIZEOF_WCHAR_T == 2:
self.assertEqual(fromwidechar('a\U0001f600'.encode(encoding), 2), 'a\ud83d')
self.assertRaises(MemoryError, fromwidechar, b'', PY_SSIZE_T_MAX)
self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, -2)
self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, PY_SSIZE_T_MIN)
self.assertEqual(fromwidechar(NULL, 0), '')
self.assertRaises(SystemError, fromwidechar, NULL, 1)
self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MAX)
self.assertRaises(SystemError, fromwidechar, NULL, -1)
self.assertRaises(SystemError, fromwidechar, NULL, -2)
self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MIN)
@support.cpython_only
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
@ -974,6 +1004,11 @@ class CAPITest(unittest.TestCase):
self.assertEqual(split('a|b|c|d', '|'), ['a', 'b', 'c', 'd'])
self.assertEqual(split('a|b|c|d', '|', 2), ['a', 'b', 'c|d'])
self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MAX),
['a', 'b', 'c', 'd'])
self.assertEqual(split('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd'])
self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MIN),
['a', 'b', 'c', 'd'])
self.assertEqual(split('a|b|c|d', '\u20ac'), ['a|b|c|d'])
self.assertEqual(split('a||b|c||d', '||'), ['a', 'b|c', 'd'])
self.assertEqual(split('а|б|в|г', '|'), ['а', 'б', 'в', 'г'])
@ -997,6 +1032,11 @@ class CAPITest(unittest.TestCase):
self.assertEqual(rsplit('a|b|c|d', '|'), ['a', 'b', 'c', 'd'])
self.assertEqual(rsplit('a|b|c|d', '|', 2), ['a|b', 'c', 'd'])
self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MAX),
['a', 'b', 'c', 'd'])
self.assertEqual(rsplit('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd'])
self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MIN),
['a', 'b', 'c', 'd'])
self.assertEqual(rsplit('a|b|c|d', '\u20ac'), ['a|b|c|d'])
self.assertEqual(rsplit('a||b|c||d', '||'), ['a', 'b|c', 'd'])
self.assertEqual(rsplit('а|б|в|г', '|'), ['а', 'б', 'в', 'г'])
@ -1129,11 +1169,14 @@ class CAPITest(unittest.TestCase):
self.assertEqual(unicode_count(str, '', 0, len(str)), len(str)+1)
# start < end
self.assertEqual(unicode_count(str, '!', 1, len(str)+1), 1)
self.assertEqual(unicode_count(str, '!', 1, PY_SSIZE_T_MAX), 1)
# start >= end
self.assertEqual(unicode_count(str, '!', 0, 0), 0)
self.assertEqual(unicode_count(str, '!', len(str), 0), 0)
# negative
self.assertEqual(unicode_count(str, '!', -len(str), -1), 1)
self.assertEqual(unicode_count(str, '!', -len(str)-1, -1), 1)
self.assertEqual(unicode_count(str, '!', PY_SSIZE_T_MIN, -1), 1)
# bad arguments
self.assertRaises(TypeError, unicode_count, str, b'!', 0, len(str))
self.assertRaises(TypeError, unicode_count, b"!>_<!", '!', 0, len(str))
@ -1152,11 +1195,11 @@ class CAPITest(unittest.TestCase):
self.assertEqual(tailmatch(str, 'aba', 0, len(str), -1), 1)
self.assertEqual(tailmatch(str, 'aha', 0, len(str), 1), 1)
self.assertEqual(tailmatch(str, 'aba', 0, sys.maxsize, -1), 1)
self.assertEqual(tailmatch(str, 'aba', -len(str), sys.maxsize, -1), 1)
self.assertEqual(tailmatch(str, 'aba', -sys.maxsize-1, len(str), -1), 1)
self.assertEqual(tailmatch(str, 'aha', 0, sys.maxsize, 1), 1)
self.assertEqual(tailmatch(str, 'aha', -sys.maxsize-1, len(str), 1), 1)
self.assertEqual(tailmatch(str, 'aba', 0, PY_SSIZE_T_MAX, -1), 1)
self.assertEqual(tailmatch(str, 'aba', -len(str), PY_SSIZE_T_MAX, -1), 1)
self.assertEqual(tailmatch(str, 'aba', PY_SSIZE_T_MIN, len(str), -1), 1)
self.assertEqual(tailmatch(str, 'aha', 0, PY_SSIZE_T_MAX, 1), 1)
self.assertEqual(tailmatch(str, 'aha', PY_SSIZE_T_MIN, len(str), 1), 1)
self.assertEqual(tailmatch(str, 'z', 0, len(str), 1), 0)
self.assertEqual(tailmatch(str, 'z', 0, len(str), -1), 0)
@ -1195,13 +1238,21 @@ class CAPITest(unittest.TestCase):
self.assertEqual(find(str, '', 0, len(str), -1), len(str))
# start < end
self.assertEqual(find(str, '!', 1, len(str)+1, 1), 4)
self.assertEqual(find(str, '!', 1, len(str)+1, -1), 4)
self.assertEqual(find(str, '!', 1, PY_SSIZE_T_MAX, 1), 4)
self.assertEqual(find(str, '!', 0, len(str)+1, -1), 4)
self.assertEqual(find(str, '!', 0, PY_SSIZE_T_MAX, -1), 4)
# start >= end
self.assertEqual(find(str, '!', 0, 0, 1), -1)
self.assertEqual(find(str, '!', 0, 0, -1), -1)
self.assertEqual(find(str, '!', len(str), 0, 1), -1)
self.assertEqual(find(str, '!', len(str), 0, -1), -1)
# negative
self.assertEqual(find(str, '!', -len(str), -1, 1), 0)
self.assertEqual(find(str, '!', -len(str), -1, -1), 0)
self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, 1), 0)
self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, -1), 0)
self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0)
self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4)
# bad arguments
self.assertRaises(TypeError, find, str, b'!', 0, len(str), 1)
self.assertRaises(TypeError, find, b"!>_<!", '!', 0, len(str), 1)
@ -1226,13 +1277,21 @@ class CAPITest(unittest.TestCase):
self.assertEqual(unicode_findchar(str, 0x110000, 0, len(str), -1), -1)
# start < end
self.assertEqual(unicode_findchar(str, ord('!'), 1, len(str)+1, 1), 4)
self.assertEqual(unicode_findchar(str, ord('!'), 1, len(str)+1, -1), 4)
self.assertEqual(unicode_findchar(str, ord('!'), 1, PY_SSIZE_T_MAX, 1), 4)
self.assertEqual(unicode_findchar(str, ord('!'), 0, len(str)+1, -1), 4)
self.assertEqual(unicode_findchar(str, ord('!'), 0, PY_SSIZE_T_MAX, -1), 4)
# start >= end
self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, 1), -1)
self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, -1), -1)
self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, 1), -1)
self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, -1), -1)
# negative
self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, 1), 0)
self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, -1), 0)
self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, 1), 0)
self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, -1), 0)
self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0)
self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4)
# bad arguments
# CRASHES unicode_findchar(b"!>_<!", ord('!'), 0, len(str), 1)
# CRASHES unicode_findchar([], ord('!'), 0, len(str), 1)
@ -1250,7 +1309,9 @@ class CAPITest(unittest.TestCase):
self.assertEqual(replace(str, 'abra', '='), '=cad=')
self.assertEqual(replace(str, 'a', '=', 2), '=br=cadabra')
self.assertEqual(replace(str, 'a', '=', 0), str)
self.assertEqual(replace(str, 'a', '=', sys.maxsize), '=br=c=d=br=')
self.assertEqual(replace(str, 'a', '=', PY_SSIZE_T_MAX), '=br=c=d=br=')
self.assertEqual(replace(str, 'a', '=', -1), '=br=c=d=br=')
self.assertEqual(replace(str, 'a', '=', PY_SSIZE_T_MIN), '=br=c=d=br=')
self.assertEqual(replace(str, 'z', '='), str)
self.assertEqual(replace(str, '', '='), '=a=b=r=a=c=a=d=a=b=r=a=')
self.assertEqual(replace(str, 'a', 'ж'), 'жbrжcжdжbrж')
@ -1386,6 +1447,9 @@ class CAPITest(unittest.TestCase):
self.assertEqual(equaltoutf8andsize(s2, b + b'x', len(b)), 1)
self.assertEqual(equaltoutf8andsize(s + '\0', b + b'\0x', len(b) + 1), 1)
self.assertEqual(equaltoutf8andsize(s2, b, len(b) - 1), 0)
self.assertEqual(equaltoutf8andsize(s, b, -1), 0)
self.assertEqual(equaltoutf8andsize(s, b, PY_SSIZE_T_MAX), 0)
self.assertEqual(equaltoutf8andsize(s, b, PY_SSIZE_T_MIN), 0)
self.assertEqual(equaltoutf8andsize('', b''), 1)
self.assertEqual(equaltoutf8andsize('', b'\0'), 0)
@ -1541,11 +1605,17 @@ class CAPITest(unittest.TestCase):
s = strings[0]
self.assertRaises(IndexError, unicode_copycharacters, s, 6, s, 0, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, PY_SSIZE_T_MAX, s, 0, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, -1, s, 0, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, PY_SSIZE_T_MIN, s, 0, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, 6, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, PY_SSIZE_T_MAX, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, -1, 5)
self.assertRaises(IndexError, unicode_copycharacters, s, 0, s, PY_SSIZE_T_MIN, 5)
self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, 5)
self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, PY_SSIZE_T_MAX)
self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, -1)
self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, PY_SSIZE_T_MIN)
self.assertRaises(SystemError, unicode_copycharacters, s, 0, b'', 0, 0)
self.assertRaises(SystemError, unicode_copycharacters, s, 0, [], 0, 0)
# CRASHES unicode_copycharacters(s, 0, NULL, 0, 0)