Skip to content
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

gh-103092: Test _ctypes type hierarchy and features #113727

Merged
merged 16 commits into from
Jan 9, 2024
Merged
23 changes: 23 additions & 0 deletions Lib/test/test_ctypes/test_arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \
c_long, c_ulonglong, c_float, c_double, c_longdouble

ArrayType = type(Array)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Structure.__base__


def ARRAY(*args):
# ignore DeprecationWarning in tests
Expand All @@ -23,6 +27,25 @@ def ARRAY(*args):


class ArrayTestCase(unittest.TestCase):
def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(Array.mro(), [Array, _CData, object])

self.assertEqual(ArrayType.__name__, "PyCArrayType")
self.assertEqual(type(ArrayType), type)

def test_instantiation(self):
with self.assertRaisesRegex(TypeError, "abstract class"):
Array()

ArrayType("Foo", (Array,), {"_length_": 1, "_type_": c_int})

def test_immutability(self):
for t in [Array, ArrayType]:
msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
t.foo = "bar"

def test_simple(self):
# create classes holding simple numeric types, and check
# various properties.
Expand Down
24 changes: 24 additions & 0 deletions Lib/test/test_ctypes/test_funcptr.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,34 @@
# fake to enable this test on Linux
WINFUNCTYPE = CFUNCTYPE


FuncPtrType = type(_CFuncPtr)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Structure.__base__

lib = CDLL(_ctypes_test.__file__)


class CFuncPtrTestCase(unittest.TestCase):
def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(_CFuncPtr.mro(), [_CFuncPtr, _CData, object])

self.assertEqual(FuncPtrType.__name__, "PyCFuncPtrType")
self.assertEqual(type(FuncPtrType), type)

def test_abstract_class(self):
with self.assertRaisesRegex(TypeError, "abstract class"):
_CFuncPtr()

FuncPtrType("Foo", (_CFuncPtr,), {"_flags_": 0})

def test_immutability(self):
for t in [_CFuncPtr, FuncPtrType]:
msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
t.foo = "bar"

def test_basic(self):
X = WINFUNCTYPE(c_int, c_int, c_int)

Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_ctypes/test_pointers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,31 @@
python_types = [int, int, int, int, int, int,
int, int, int, int, float, float]

PointerType = type(_Pointer)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Structure.__base__


class PointersTestCase(unittest.TestCase):
def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(_Pointer.mro(), [_Pointer, _CData, object])

self.assertEqual(PointerType.__name__, "PyCPointerType")
self.assertEqual(type(PointerType), type)

def test_abstract_class(self):
with self.assertRaisesRegex(TypeError, "Cannot create instance: has no _type"):
_Pointer()

PointerType("Foo", (_Pointer,), {})

def test_immutability(self):
for t in [_Pointer, PointerType]:
msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
t.foo = "bar"

def test_pointer_crash(self):

class A(POINTER(c_ulong)):
Expand Down
28 changes: 27 additions & 1 deletion Lib/test/test_ctypes/test_simplesubclasses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import unittest
from ctypes import Structure, CFUNCTYPE, c_int
from ctypes import Structure, CFUNCTYPE, c_int, _SimpleCData


SimpleType = type(_SimpleCData)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Structure.__base__


class MyInt(c_int):
Expand All @@ -10,6 +15,27 @@ def __eq__(self, other):


class Test(unittest.TestCase):
def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(_SimpleCData.mro(), [_SimpleCData, _CData, object])

self.assertEqual(SimpleType.__name__, "PyCSimpleType")
self.assertEqual(type(SimpleType), type)

self.assertEqual(c_int.mro(), [c_int, _SimpleCData, _CData, object])

def test_abstract_class(self):
with self.assertRaisesRegex(TypeError, "abstract class"):
_SimpleCData()

SimpleType("Foo", (_SimpleCData,), {"_type_": "i"})

def test_immutability(self):
for t in [_SimpleCData, SimpleType]:
msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
t.foo = "bar"


def test_compare(self):
self.assertEqual(MyInt(3), MyInt(3))
Expand Down
14 changes: 12 additions & 2 deletions Lib/test/test_ctypes/test_struct_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,21 @@ class X(Structure):
x.char = b'a\0b\0'
self.assertEqual(bytes(x), b'a\x00###')

def test_6(self):
def test_cfield_instantiation(self):
class X(Structure):
_fields_ = [("x", c_int)]
CField = type(X.x)
self.assertRaises(TypeError, CField)
self.assertRaisesRegex(TypeError,
"cannot create '_ctypes.CField' instances",
CField)

def test_cfield_immutability(self):
class X(Structure):
_fields_ = [("x", c_int)]
CField = type(X.x)
msg = "cannot set 'foo' attribute of immutable type '_ctypes.CField'"
with self.assertRaisesRegex(TypeError, msg):
CField.foo = "bar"

def test_gh99275(self):
class BrokenStructure(Structure):
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_ctypes/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
from collections import namedtuple
from test import support

StructureType = type(Structure)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Array.__base__


class SubclassesTest(unittest.TestCase):
def test_subclass(self):
Expand Down Expand Up @@ -70,6 +74,25 @@ class StructureTestCase(unittest.TestCase):
"d": c_double,
}

def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(Structure.mro(), [Structure, _CData, object])

self.assertEqual(StructureType.__name__, "PyCStructType")
self.assertEqual(type(StructureType), type)

def test_instantiation(self):
with self.assertRaisesRegex(TypeError, "abstract class"):
Structure()

StructureType("Foo", (Structure,), {})

def test_immutability(self):
for t in [Structure, StructureType]:
msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
t.foo = "bar"

def test_simple_structs(self):
for code, tp in self.formats.items():
class X(Structure):
Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_ctypes/test_unions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import ctypes
import sys
import unittest
import warnings
from ctypes import Union


UnionType = type(Union)
# _CData is not exported to Python, so we have to access it from __base__.
_CData = Union.__base__


class ArrayTestCase(unittest.TestCase):
def test_inheritance_hierarchy(self):
self.assertEqual(_CData.__name__, "_CData")
self.assertEqual(Union.mro(), [Union, _CData, object])

self.assertEqual(UnionType.__name__, "UnionType")
self.assertEqual(type(UnionType), type)

def test_instantiation(self):
with self.assertRaisesRegex(TypeError, "abstract class"):
Union()

UnionType("Foo", (Union,), {})

def test_immutability(self):
Union.foo = "bar"

msg = "cannot set 'foo' attribute of immutable type"
with self.assertRaisesRegex(TypeError, msg):
UnionType.foo = "bar"