8000 Add test_ctypes from CPython 3.11 by fanninpm · Pull Request #4458 · RustPython/RustPython · GitHub
[go: up one dir, main page]

Skip to content

Add test_ctypes from CPython 3.11 #4458

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 2 commits into from
Jan 18, 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
16 changes: 16 additions & 0 deletions Lib/ctypes/test/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import os
import unittest
from test import support
from test.support import import_helper


# skip tests if _ctypes was not built
ctypes = import_helper.import_module('ctypes')
ctypes_symbols = dir(ctypes)

def need_symbol(name):
return unittest.skipUnless(name in ctypes_symbols,
'{!r} is required'.format(name))

def load_tests(*args):
return support.load_package_tests(os.path.dirname(__file__), *args)
4 changes: 4 additions & 0 deletions Lib/ctypes/test/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from ctypes.test import load_tests
import unittest

unittest.main()
73 changes: 73 additions & 0 deletions Lib/ctypes/test/test_anon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import unittest
import test.support
from ctypes import *

class AnonTest(unittest.TestCase):

def test_anon(self):
class ANON(Union):
_fields_ = [("a", c_int),
("b", c_int)]

class Y(Structure):
_fields_ = [("x", c_int),
("_", ANON),
("y", c_int)]
_anonymous_ = ["_"]

self.assertEqual(Y.a.offset, sizeof(c_int))
self.assertEqual(Y.b.offset, sizeof(c_int))

self.assertEqual(ANON.a.offset, 0)
self.assertEqual(ANON.b.offset, 0)

def test_anon_nonseq(self):
# TypeError: _anonymous_ must be a sequence
self.assertRaises(TypeError,
lambda: type(Structure)("Name",
(Structure,),
{"_fields_": [], "_anonymous_": 42}))

def test_anon_nonmember(self):
# AttributeError: type object 'Name' has no attribute 'x'
self.assertRaises(AttributeError,
lambda: type(Structure)("Name",
(Structure,),
{"_fields_": [],
"_anonymous_": ["x"]}))

@test.support.cpython_only
def test_issue31490(self):
# There shouldn't be an assertion failure in case the class has an
# attribute whose name is specified in _anonymous_ but not in _fields_.

# AttributeError: 'x' is specified in _anonymous_ but not in _fields_
with self.assertRaises(AttributeError):
class Name(Structure):
_fields_ = []
_anonymous_ = ["x"]
x = 42

def test_nested(self):
class ANON_S(Structure):
_fields_ = [("a", c_int)]

class ANON_U(Union):
_fields_ = [("_", ANON_S),
("b", c_int)]
_anonymous_ = ["_"]

class Y(Structure):
_fields_ = [("x", c_int),
("_", ANON_U),
("y", c_int)]
_anonymous_ = ["_"]

self.assertEqual(Y.x.offset, 0)
self.assertEqual(Y.a.offset, sizeof(c_int))
self.assertEqual(Y.b.offset, sizeof(c_int))
self.assertEqual(Y._.offset, sizeof(c_int))
self.assertEqual(Y.y.offset, sizeof(c_int) * 2)

if __name__ == "__main__":
unittest.main()
64 changes: 64 additions & 0 deletions Lib/ctypes/test/test_array_in_pointer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import unittest
from ctypes import *
from binascii import hexlify
import re

def dump(obj):
# helper function to dump memory contents in hex, with a hyphen
# between the bytes.
h = hexlify(memoryview(obj)).decode()
return re.sub(r"(..)", r"\1-", h)[:-1]


class Value(Structure):
_fields_ = [("val", c_byte)]

class Container(Structure):
_fields_ = [("pvalues", POINTER(Value))]

class Test(unittest.TestCase):
def test(self):
# create an array of 4 values
val_array = (Value * 4)()

# create a container, which holds a pointer to the pvalues array.
c = Container()
c.pvalues = val_array

# memory contains 4 NUL bytes now, that's correct
self.assertEqual("00-00-00-00", dump(val_array))

# set the values of the array through the pointer:
for i in range(4):
c.pvalues[i].val = i + 1

values = [c.pvalues[i].val for i in range(4)]

# These are the expected results: here s the bug!
self.assertEqual(
(values, dump(val_array)),
([1, 2, 3, 4], "01-02-03-04")
)

def test_2(self):

val_array = (Value * 4)()

# memory contains 4 NUL bytes now, that's correct
self.assertEqual("00-00-00-00", dump(val_array))

ptr = cast(val_array, POINTER(Value))
# set the values of the array through the pointer:
for i in range(4):
ptr[i].val = i + 1

values = [ptr[i].val for i in range(4)]

# These are the expected results: here s the bug!
self.assertEqual(
(values, dump(val_array)),
([1, 2, 3, 4], "01-02-03-04")
)

if __name__ == "__main__":
unittest.main()
238 changes: 238 additions & 0 deletions Lib/ctypes/test/test_arrays.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import unittest
from test.support import bigmemtest, _2G
import sys
from ctypes import *

from ctypes.test import need_symbol

formats = "bBhHiIlLqQfd"

formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \
c_long, c_ulonglong, c_float, c_double, c_longdouble

class ArrayTestCase(unittest.TestCase):
def test_simple(self):
# create classes holding simple numeric types, and check
# various properties.

init = list(range(15, 25))

for fmt in formats:
alen = len(init)
int_array = ARRAY(fmt, alen)

ia = int_array(*init)
# length of instance ok?
self.assertEqual(len(ia), alen)

# slot values ok?
values = [ia[i] for i in range(alen)]
self.assertEqual(values, init)

# out-of-bounds accesses should be caught
with self.assertRaises(IndexError): ia[alen]
with self.assertRaises(IndexError): ia[-alen-1]

# change the items
from operator import setitem
new_values = list(range(42, 42+alen))
[setitem(ia, n, new_values[n]) for n in range(alen)]
values = [ia[i] for i in range(alen)]
self.assertEqual(values, new_values)

# are the items initialized to 0?
ia = int_array()
values = [ia[i] for i in range(alen)]
self.assertEqual(values, [0] * alen)

# Too many initializers should be caught
self.assertRaises(IndexError, int_array, *range(alen*2))

CharArray = ARRAY(c_char, 3)

ca = CharArray(b"a", b"b", b"c")

# Should this work? It doesn't:
# CharArray("abc")
self.assertRaises(TypeError, CharArray, "abc")

self.assertEqual(ca[0], b"a")
self.assertEqual(ca[1], b"b")
self.assertEqual(ca[2], b"c")
self.assertEqual(ca[-3], b"a")
self.assertEqual(ca[-2], b"b")
self.assertEqual(ca[-1], b"c")

self.assertEqual(len(ca), 3)

# cannot delete items
from operator import delitem
self.assertRaises(TypeError, delitem, ca, 0)

def test_step_overflow(self):
a = (c_int * 5)()
a[3::sys.maxsize] = (1,)
self.assertListEqual(a[3::sys.maxsize], [1])
a = (c_char * 5)()
a[3::sys.maxsize] = b"A"
self.assertEqual(a[3::sys.maxsize], b"A")
a = (c_wchar * 5)()
a[3::sys.maxsize] = u"X"
self.assertEqual(a[3::sys.maxsize], u"X")

def test_numeric_arrays(self):

alen = 5

numarray = ARRAY(c_int, alen)

na = numarray()
values = [na[i] for i in range(alen)]
self.assertEqual(values, [0] * alen)

na = numarray(*[c_int()] * alen)
values = [na[i] for i in range(alen)]
self.assertEqual(values, [0]*alen)

na = numarray(1, 2, 3, 4, 5)
values = [i for i in na]
self.assertEqual(values, [1, 2, 3, 4, 5])

na = numarray(*map(c_int, (1, 2, 3, 4, 5)))
values = [i for i in na]
self.assertEqual(values, [1, 2, 3, 4, 5])

def test_classcache(self):
self.assertIsNot(ARRAY(c_int, 3), ARRAY(c_int, 4))
self.assertIs(ARRAY(c_int, 3), ARRAY(c_int, 3))

def test_from_address(self):
# Failed with 0.9.8, reported by JUrner
p = create_string_buffer(b"foo")
sz = (c_char * 3).from_address(addressof(p))
self.assertEqual(sz[:], b"foo")
self.assertEqual(sz[::], b"foo")
self.assertEqual(sz[::-1], b"oof")
self.assertEqual(sz[::3], b"f")
self.assertEqual(sz[1:4:2], b"o")
self.assertEqual(sz.value, b"foo")

@need_symbol('create_unicode_buffer')
def test_from_addressW(self):
p = create_unicode_buffer("foo")
sz = (c_wchar * 3).from_address(addressof(p))
self.assertEqual(sz[:], "foo")
self.assertEqual(sz[::], "foo")
self.assertEqual(sz[::-1], "oof")
self.assertEqual(sz[::3], "f")
self.assertEqual(sz[1:4:2], "o")
self.assertEqual(sz.value, "foo")

def test_cache(self):
# Array types are cached internally in the _ctypes extension,
# in a WeakValueDictionary. Make sure the array type is
# removed from the cache when the itemtype goes away. This
# test will not fail, but will show a leak in the testsuite.

# Create a new type:
class my_int(c_int):
pass
# Create a new array type based on it:
t1 = my_int * 1
t2 = my_int * 1
self.assertIs(t1, t2)

def test_subclass(self):
class T(Array):
_type_ = c_int
_length_ = 13
class U(T):
pass
class V(U):
pass
class W(V):
pass
class X(T):
_type_ = c_short
class Y(T):
_length_ = 187

for c in [T, U, V, W]:
self.assertEqual(c._type_, c_int)
self.assertEqual(c._length_, 13)
self.assertEqual(c()._type_, c_int)
self.assertEqual(c()._length_, 13)

self.assertEqual(X._type_, c_short)
self.assertEqual(X._length_, 13)
self.assertEqual(X()._type_, c_short)
self.assertEqual(X()._length_, 13)

self.assertEqual(Y._type_, c_int)
self.assertEqual(Y._length_, 187)
self.assertEqual(Y()._type_, c_int)
self.assertEqual(Y()._length_, 187)

def test_bad_subclass(self):
with self.assertRaises(AttributeError):
class T(Array):
pass
with self.assertRaises(AttributeError):
class T(Array):
_type_ = c_int
with self.assertRaises(AttributeError):
class T(Array):
_length_ = 13

def test_bad_length(self):
with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
_length_ = - sys.maxsize * 2
with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
_length_ = -1
with self.assertRaises(TypeError):
class T(Array):
_type_ = c_int
_length_ = 1.87
with self.assertRaises(OverflowError):
class T(Array):
_type_ = c_int
_length_ = sys.maxsize * 2

def test_zero_length(self):
# _length_ can be zero.
class T(Array):
_type_ = c_int
_length_ = 0

def test_empty_element_struct(self):
class EmptyStruct(Structure):
_fields_ = []

obj = (EmptyStruct * 2)() # bpo37188: Floating point exception
self.assertEqual(sizeof(obj), 0)

def test_empty_element_array(self):
class EmptyArray(Array):
_type_ = c_int
_length_ = 0

obj = (EmptyArray * 2)() # bpo37188: Floating point exception
self.assertEqual(sizeof(obj), 0)

def test_bpo36504_signed_int_overflow(self):
# The overflow check in PyCArrayType_new() could cause signed integer
# overflow.
with self.assertRaises(OverflowError):
c_char * sys.maxsize * 2

@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
@bigmemtest(size=_2G, memuse=1, dry_run=False)
def test_large_array(self, size):
c_char * size

if __name__ == '__main__':
unittest.main()
Loading
0