Merge pull request #4458 from fanninpm/test-ctypes

Add test_ctypes from CPython 3.11
This commit is contained in:
Jeong YunWon
2023-01-18 13:32:04 +09:00
committed by GitHub
54 changed files with 7313 additions and 0 deletions

16
Lib/ctypes/test/__init__.py vendored Normal file
View File

@@ -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
Lib/ctypes/test/__main__.py vendored Normal file
View File

@@ -0,0 +1,4 @@
from ctypes.test import load_tests
import unittest
unittest.main()

73
Lib/ctypes/test/test_anon.py vendored Normal file
View File

@@ -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()

View File

@@ -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
Lib/ctypes/test/test_arrays.py vendored Normal file
View File

@@ -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()

231
Lib/ctypes/test/test_as_parameter.py vendored Normal file
View File

@@ -0,0 +1,231 @@
import unittest
from ctypes import *
from ctypes.test import need_symbol
import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
try:
CALLBACK_FUNCTYPE = WINFUNCTYPE
except NameError:
# fake to enable this test on Linux
CALLBACK_FUNCTYPE = CFUNCTYPE
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
class BasicWrapTestCase(unittest.TestCase):
def wrap(self, param):
return param
@need_symbol('c_wchar')
def test_wchar_parm(self):
f = dll._testfunc_i_bhilfd
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
result = f(self.wrap(1), self.wrap("x"), self.wrap(3), self.wrap(4), self.wrap(5.0), self.wrap(6.0))
self.assertEqual(result, 139)
self.assertIs(type(result), int)
def test_pointers(self):
f = dll._testfunc_p_p
f.restype = POINTER(c_int)
f.argtypes = [POINTER(c_int)]
# This only works if the value c_int(42) passed to the
# function is still alive while the pointer (the result) is
# used.
v = c_int(42)
self.assertEqual(pointer(v).contents.value, 42)
result = f(self.wrap(pointer(v)))
self.assertEqual(type(result), POINTER(c_int))
self.assertEqual(result.contents.value, 42)
# This on works...
result = f(self.wrap(pointer(v)))
self.assertEqual(result.contents.value, v.value)
p = pointer(c_int(99))
result = f(self.wrap(p))
self.assertEqual(result.contents.value, 99)
def test_shorts(self):
f = dll._testfunc_callback_i_if
args = []
expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
def callback(v):
args.append(v)
return v
CallBack = CFUNCTYPE(c_int, c_int)
cb = CallBack(callback)
f(self.wrap(2**18), self.wrap(cb))
self.assertEqual(args, expected)
################################################################
def test_callbacks(self):
f = dll._testfunc_callback_i_if
f.restype = c_int
f.argtypes = None
MyCallback = CFUNCTYPE(c_int, c_int)
def callback(value):
#print "called back with", value
return value
cb = MyCallback(callback)
result = f(self.wrap(-10), self.wrap(cb))
self.assertEqual(result, -18)
# test with prototype
f.argtypes = [c_int, MyCallback]
cb = MyCallback(callback)
result = f(self.wrap(-10), self.wrap(cb))
self.assertEqual(result, -18)
result = f(self.wrap(-10), self.wrap(cb))
self.assertEqual(result, -18)
AnotherCallback = CALLBACK_FUNCTYPE(c_int, c_int, c_int, c_int, c_int)
# check that the prototype works: we call f with wrong
# argument types
cb = AnotherCallback(callback)
self.assertRaises(ArgumentError, f, self.wrap(-10), self.wrap(cb))
def test_callbacks_2(self):
# Can also use simple datatypes as argument type specifiers
# for the callback function.
# In this case the call receives an instance of that type
f = dll._testfunc_callback_i_if
f.restype = c_int
MyCallback = CFUNCTYPE(c_int, c_int)
f.argtypes = [c_int, MyCallback]
def callback(value):
#print "called back with", value
self.assertEqual(type(value), int)
return value
cb = MyCallback(callback)
result = f(self.wrap(-10), self.wrap(cb))
self.assertEqual(result, -18)
@need_symbol('c_longlong')
def test_longlong_callbacks(self):
f = dll._testfunc_callback_q_qf
f.restype = c_longlong
MyCallback = CFUNCTYPE(c_longlong, c_longlong)
f.argtypes = [c_longlong, MyCallback]
def callback(value):
self.assertIsInstance(value, int)
return value & 0x7FFFFFFF
cb = MyCallback(callback)
self.assertEqual(13577625587, int(f(self.wrap(1000000000000), self.wrap(cb))))
def test_byval(self):
# without prototype
ptin = POINT(1, 2)
ptout = POINT()
# EXPORT int _testfunc_byval(point in, point *pout)
result = dll._testfunc_byval(ptin, byref(ptout))
got = result, ptout.x, ptout.y
expected = 3, 1, 2
self.assertEqual(got, expected)
# with prototype
ptin = POINT(101, 102)
ptout = POINT()
dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
dll._testfunc_byval.restype = c_int
result = dll._testfunc_byval(self.wrap(ptin), byref(ptout))
got = result, ptout.x, ptout.y
expected = 203, 101, 102
self.assertEqual(got, expected)
def test_struct_return_2H(self):
class S2H(Structure):
_fields_ = [("x", c_short),
("y", c_short)]
dll.ret_2h_func.restype = S2H
dll.ret_2h_func.argtypes = [S2H]
inp = S2H(99, 88)
s2h = dll.ret_2h_func(self.wrap(inp))
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
# Test also that the original struct was unmodified (i.e. was passed by
# value)
self.assertEqual((inp.x, inp.y), (99, 88))
def test_struct_return_8H(self):
class S8I(Structure):
_fields_ = [("a", c_int),
("b", c_int),
("c", c_int),
("d", c_int),
("e", c_int),
("f", c_int),
("g", c_int),
("h", c_int)]
dll.ret_8i_func.restype = S8I
dll.ret_8i_func.argtypes = [S8I]
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
s8i = dll.ret_8i_func(self.wrap(inp))
self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
def test_recursive_as_param(self):
from ctypes import c_int
class A(object):
pass
a = A()
a._as_parameter_ = a
with self.assertRaises(RecursionError):
c_int.from_param(a)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AsParamWrapper(object):
def __init__(self, param):
self._as_parameter_ = param
class AsParamWrapperTestCase(BasicWrapTestCase):
wrap = AsParamWrapper
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AsParamPropertyWrapper(object):
def __init__(self, param):
self._param = param
def getParameter(self):
return self._param
_as_parameter_ = property(getParameter)
class AsParamPropertyWrapperTestCase(BasicWrapTestCase):
wrap = AsParamPropertyWrapper
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == '__main__':
unittest.main()

297
Lib/ctypes/test/test_bitfields.py vendored Normal file
View File

@@ -0,0 +1,297 @@
from ctypes import *
from ctypes.test import need_symbol
from test import support
import unittest
import os
import _ctypes_test
class BITS(Structure):
_fields_ = [("A", c_int, 1),
("B", c_int, 2),
("C", c_int, 3),
("D", c_int, 4),
("E", c_int, 5),
("F", c_int, 6),
("G", c_int, 7),
("H", c_int, 8),
("I", c_int, 9),
("M", c_short, 1),
("N", c_short, 2),
("O", c_short, 3),
("P", c_short, 4),
("Q", c_short, 5),
("R", c_short, 6),
("S", c_short, 7)]
func = CDLL(_ctypes_test.__file__).unpack_bitfields
func.argtypes = POINTER(BITS), c_char
##for n in "ABCDEFGHIMNOPQRS":
## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset
class C_Test(unittest.TestCase):
def test_ints(self):
for i in range(512):
for name in "ABCDEFGHI":
b = BITS()
setattr(b, name, i)
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))
# bpo-46913: _ctypes/cfield.c h_get() has an undefined behavior
@support.skip_if_sanitizer(ub=True)
def test_shorts(self):
b = BITS()
name = "M"
if func(byref(b), name.encode('ascii')) == 999:
self.skipTest("Compiler does not support signed short bitfields")
for i in range(256):
for name in "MNOPQRS":
b = BITS()
setattr(b, name, i)
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))
signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong)
unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong)
int_types = unsigned_int_types + signed_int_types
class BitFieldTest(unittest.TestCase):
def test_longlong(self):
class X(Structure):
_fields_ = [("a", c_longlong, 1),
("b", c_longlong, 62),
("c", c_longlong, 1)]
self.assertEqual(sizeof(X), sizeof(c_longlong))
x = X()
x.a, x.b, x.c = -1, 7, -1
self.assertEqual((x.a, x.b, x.c), (-1, 7, -1))
def test_ulonglong(self):
class X(Structure):
_fields_ = [("a", c_ulonglong, 1),
("b", c_ulonglong, 62),
("c", c_ulonglong, 1)]
self.assertEqual(sizeof(X), sizeof(c_longlong))
x = X()
self.assertEqual((x.a, x.b, x.c), (0, 0, 0))
x.a, x.b, x.c = 7, 7, 7
self.assertEqual((x.a, x.b, x.c), (1, 7, 1))
def test_signed(self):
for c_typ in signed_int_types:
class X(Structure):
_fields_ = [("dummy", c_typ),
("a", c_typ, 3),
("b", c_typ, 3),
("c", c_typ, 1)]
self.assertEqual(sizeof(X), sizeof(c_typ)*2)
x = X()
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0))
x.a = -1
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, -1, 0, 0))
x.a, x.b = 0, -1
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, -1, 0))
def test_unsigned(self):
for c_typ in unsigned_int_types:
class X(Structure):
_fields_ = [("a", c_typ, 3),
("b", c_typ, 3),
("c", c_typ, 1)]
self.assertEqual(sizeof(X), sizeof(c_typ))
x = X()
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0))
x.a = -1
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 7, 0, 0))
x.a, x.b = 0, -1
self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0))
def fail_fields(self, *fields):
return self.get_except(type(Structure), "X", (),
{"_fields_": fields})
def test_nonint_types(self):
# bit fields are not allowed on non-integer types.
result = self.fail_fields(("a", c_char_p, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char_p'))
result = self.fail_fields(("a", c_void_p, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_void_p'))
if c_int != c_long:
result = self.fail_fields(("a", POINTER(c_int), 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type LP_c_int'))
result = self.fail_fields(("a", c_char, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type c_char'))
class Dummy(Structure):
_fields_ = []
result = self.fail_fields(("a", Dummy, 1))
self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy'))
@need_symbol('c_wchar')
def test_c_wchar(self):
result = self.fail_fields(("a", c_wchar, 1))
self.assertEqual(result,
(TypeError, 'bit fields not allowed for type c_wchar'))
def test_single_bitfield_size(self):
for c_typ in int_types:
result = self.fail_fields(("a", c_typ, -1))
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
result = self.fail_fields(("a", c_typ, 0))
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
class X(Structure):
_fields_ = [("a", c_typ, 1)]
self.assertEqual(sizeof(X), sizeof(c_typ))
class X(Structure):
_fields_ = [("a", c_typ, sizeof(c_typ)*8)]
self.assertEqual(sizeof(X), sizeof(c_typ))
result = self.fail_fields(("a", c_typ, sizeof(c_typ)*8 + 1))
self.assertEqual(result, (ValueError, 'number of bits invalid for bit field'))
def test_multi_bitfields_size(self):
class X(Structure):
_fields_ = [("a", c_short, 1),
("b", c_short, 14),
("c", c_short, 1)]
self.assertEqual(sizeof(X), sizeof(c_short))
class X(Structure):
_fields_ = [("a", c_short, 1),
("a1", c_short),
("b", c_short, 14),
("c", c_short, 1)]
self.assertEqual(sizeof(X), sizeof(c_short)*3)
self.assertEqual(X.a.offset, 0)
self.assertEqual(X.a1.offset, sizeof(c_short))
self.assertEqual(X.b.offset, sizeof(c_short)*2)
self.assertEqual(X.c.offset, sizeof(c_short)*2)
class X(Structure):
_fields_ = [("a", c_short, 3),
("b", c_short, 14),
("c", c_short, 14)]
self.assertEqual(sizeof(X), sizeof(c_short)*3)
self.assertEqual(X.a.offset, sizeof(c_short)*0)
self.assertEqual(X.b.offset, sizeof(c_short)*1)
self.assertEqual(X.c.offset, sizeof(c_short)*2)
def get_except(self, func, *args, **kw):
try:
func(*args, **kw)
except Exception as detail:
return detail.__class__, str(detail)
def test_mixed_1(self):
class X(Structure):
_fields_ = [("a", c_byte, 4),
("b", c_int, 4)]
if os.name == "nt":
self.assertEqual(sizeof(X), sizeof(c_int)*2)
else:
self.assertEqual(sizeof(X), sizeof(c_int))
def test_mixed_2(self):
class X(Structure):
_fields_ = [("a", c_byte, 4),
("b", c_int, 32)]
self.assertEqual(sizeof(X), alignment(c_int)+sizeof(c_int))
def test_mixed_3(self):
class X(Structure):
_fields_ = [("a", c_byte, 4),
("b", c_ubyte, 4)]
self.assertEqual(sizeof(X), sizeof(c_byte))
def test_mixed_4(self):
class X(Structure):
_fields_ = [("a", c_short, 4),
("b", c_short, 4),
("c", c_int, 24),
("d", c_short, 4),
("e", c_short, 4),
("f", c_int, 24)]
# MSVC does NOT combine c_short and c_int into one field, GCC
# does (unless GCC is run with '-mms-bitfields' which
# produces code compatible with MSVC).
if os.name == "nt":
self.assertEqual(sizeof(X), sizeof(c_int) * 4)
else:
self.assertEqual(sizeof(X), sizeof(c_int) * 2)
def test_anon_bitfields(self):
# anonymous bit-fields gave a strange error message
class X(Structure):
_fields_ = [("a", c_byte, 4),
("b", c_ubyte, 4)]
class Y(Structure):
_anonymous_ = ["_"]
_fields_ = [("_", X)]
@need_symbol('c_uint32')
def test_uint32(self):
class X(Structure):
_fields_ = [("a", c_uint32, 32)]
x = X()
x.a = 10
self.assertEqual(x.a, 10)
x.a = 0xFDCBA987
self.assertEqual(x.a, 0xFDCBA987)
@need_symbol('c_uint64')
def test_uint64(self):
class X(Structure):
_fields_ = [("a", c_uint64, 64)]
x = X()
x.a = 10
self.assertEqual(x.a, 10)
x.a = 0xFEDCBA9876543211
self.assertEqual(x.a, 0xFEDCBA9876543211)
@need_symbol('c_uint32')
def test_uint32_swap_little_endian(self):
# Issue #23319
class Little(LittleEndianStructure):
_fields_ = [("a", c_uint32, 24),
("b", c_uint32, 4),
("c", c_uint32, 4)]
b = bytearray(4)
x = Little.from_buffer(b)
x.a = 0xabcdef
x.b = 1
x.c = 2
self.assertEqual(b, b'\xef\xcd\xab\x21')
@need_symbol('c_uint32')
def test_uint32_swap_big_endian(self):
# Issue #23319
class Big(BigEndianStructure):
_fields_ = [("a", c_uint32, 24),
("b", c_uint32, 4),
("c", c_uint32, 4)]
b = bytearray(4)
x = Big.from_buffer(b)
x.a = 0xabcdef
x.b = 1
x.c = 2
self.assertEqual(b, b'\xab\xcd\xef\x12')
if __name__ == "__main__":
unittest.main()

73
Lib/ctypes/test/test_buffers.py vendored Normal file
View File

@@ -0,0 +1,73 @@
from ctypes import *
from ctypes.test import need_symbol
import unittest
class StringBufferTestCase(unittest.TestCase):
def test_buffer(self):
b = create_string_buffer(32)
self.assertEqual(len(b), 32)
self.assertEqual(sizeof(b), 32 * sizeof(c_char))
self.assertIs(type(b[0]), bytes)
b = create_string_buffer(b"abc")
self.assertEqual(len(b), 4) # trailing nul char
self.assertEqual(sizeof(b), 4 * sizeof(c_char))
self.assertIs(type(b[0]), bytes)
self.assertEqual(b[0], b"a")
self.assertEqual(b[:], b"abc\0")
self.assertEqual(b[::], b"abc\0")
self.assertEqual(b[::-1], b"\0cba")
self.assertEqual(b[::2], b"ac")
self.assertEqual(b[::5], b"a")
self.assertRaises(TypeError, create_string_buffer, "abc")
def test_buffer_interface(self):
self.assertEqual(len(bytearray(create_string_buffer(0))), 0)
self.assertEqual(len(bytearray(create_string_buffer(1))), 1)
@need_symbol('c_wchar')
def test_unicode_buffer(self):
b = create_unicode_buffer(32)
self.assertEqual(len(b), 32)
self.assertEqual(sizeof(b), 32 * sizeof(c_wchar))
self.assertIs(type(b[0]), str)
b = create_unicode_buffer("abc")
self.assertEqual(len(b), 4) # trailing nul char
self.assertEqual(sizeof(b), 4 * sizeof(c_wchar))
self.assertIs(type(b[0]), str)
self.assertEqual(b[0], "a")
self.assertEqual(b[:], "abc\0")
self.assertEqual(b[::], "abc\0")
self.assertEqual(b[::-1], "\0cba")
self.assertEqual(b[::2], "ac")
self.assertEqual(b[::5], "a")
self.assertRaises(TypeError, create_unicode_buffer, b"abc")
@need_symbol('c_wchar')
def test_unicode_conversion(self):
b = create_unicode_buffer("abc")
self.assertEqual(len(b), 4) # trailing nul char
self.assertEqual(sizeof(b), 4 * sizeof(c_wchar))
self.assertIs(type(b[0]), str)
self.assertEqual(b[0], "a")
self.assertEqual(b[:], "abc\0")
self.assertEqual(b[::], "abc\0")
self.assertEqual(b[::-1], "\0cba")
self.assertEqual(b[::2], "ac")
self.assertEqual(b[::5], "a")
@need_symbol('c_wchar')
def test_create_unicode_buffer_non_bmp(self):
expected = 5 if sizeof(c_wchar) == 2 else 3
for s in '\U00010000\U00100000', '\U00010000\U0010ffff':
b = create_unicode_buffer(s)
self.assertEqual(len(b), expected)
self.assertEqual(b[-1], '\0')
if __name__ == "__main__":
unittest.main()

66
Lib/ctypes/test/test_bytes.py vendored Normal file
View File

@@ -0,0 +1,66 @@
"""Test where byte objects are accepted"""
import unittest
import sys
from ctypes import *
class BytesTest(unittest.TestCase):
def test_c_char(self):
x = c_char(b"x")
self.assertRaises(TypeError, c_char, "x")
x.value = b"y"
with self.assertRaises(TypeError):
x.value = "y"
c_char.from_param(b"x")
self.assertRaises(TypeError, c_char.from_param, "x")
self.assertIn('xbd', repr(c_char.from_param(b"\xbd")))
(c_char * 3)(b"a", b"b", b"c")
self.assertRaises(TypeError, c_char * 3, "a", "b", "c")
def test_c_wchar(self):
x = c_wchar("x")
self.assertRaises(TypeError, c_wchar, b"x")
x.value = "y"
with self.assertRaises(TypeError):
x.value = b"y"
c_wchar.from_param("x")
self.assertRaises(TypeError, c_wchar.from_param, b"x")
(c_wchar * 3)("a", "b", "c")
self.assertRaises(TypeError, c_wchar * 3, b"a", b"b", b"c")
def test_c_char_p(self):
c_char_p(b"foo bar")
self.assertRaises(TypeError, c_char_p, "foo bar")
def test_c_wchar_p(self):
c_wchar_p("foo bar")
self.assertRaises(TypeError, c_wchar_p, b"foo bar")
def test_struct(self):
class X(Structure):
_fields_ = [("a", c_char * 3)]
x = X(b"abc")
self.assertRaises(TypeError, X, "abc")
self.assertEqual(x.a, b"abc")
self.assertEqual(type(x.a), bytes)
def test_struct_W(self):
class X(Structure):
_fields_ = [("a", c_wchar * 3)]
x = X("abc")
self.assertRaises(TypeError, X, b"abc")
self.assertEqual(x.a, "abc")
self.assertEqual(type(x.a), str)
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
def test_BSTR(self):
from _ctypes import _SimpleCData
class BSTR(_SimpleCData):
_type_ = "X"
BSTR("abc")
if __name__ == '__main__':
unittest.main()

364
Lib/ctypes/test/test_byteswap.py vendored Normal file
View File

@@ -0,0 +1,364 @@
import sys, unittest, struct, math, ctypes
from binascii import hexlify
from ctypes import *
def bin(s):
return hexlify(memoryview(s)).decode().upper()
# Each *simple* type that supports different byte orders has an
# __ctype_be__ attribute that specifies the same type in BIG ENDIAN
# byte order, and a __ctype_le__ attribute that is the same type in
# LITTLE ENDIAN byte order.
#
# For Structures and Unions, these types are created on demand.
class Test(unittest.TestCase):
@unittest.skip('test disabled')
def test_X(self):
print(sys.byteorder, file=sys.stderr)
for i in range(32):
bits = BITS()
setattr(bits, "i%s" % i, 1)
dump(bits)
def test_slots(self):
class BigPoint(BigEndianStructure):
__slots__ = ()
_fields_ = [("x", c_int), ("y", c_int)]
class LowPoint(LittleEndianStructure):
__slots__ = ()
_fields_ = [("x", c_int), ("y", c_int)]
big = BigPoint()
little = LowPoint()
big.x = 4
big.y = 2
little.x = 2
little.y = 4
with self.assertRaises(AttributeError):
big.z = 42
with self.assertRaises(AttributeError):
little.z = 24
def test_endian_short(self):
if sys.byteorder == "little":
self.assertIs(c_short.__ctype_le__, c_short)
self.assertIs(c_short.__ctype_be__.__ctype_le__, c_short)
else:
self.assertIs(c_short.__ctype_be__, c_short)
self.assertIs(c_short.__ctype_le__.__ctype_be__, c_short)
s = c_short.__ctype_be__(0x1234)
self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
self.assertEqual(bin(s), "1234")
self.assertEqual(s.value, 0x1234)
s = c_short.__ctype_le__(0x1234)
self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
self.assertEqual(bin(s), "3412")
self.assertEqual(s.value, 0x1234)
s = c_ushort.__ctype_be__(0x1234)
self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
self.assertEqual(bin(s), "1234")
self.assertEqual(s.value, 0x1234)
s = c_ushort.__ctype_le__(0x1234)
self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
self.assertEqual(bin(s), "3412")
self.assertEqual(s.value, 0x1234)
def test_endian_int(self):
if sys.byteorder == "little":
self.assertIs(c_int.__ctype_le__, c_int)
self.assertIs(c_int.__ctype_be__.__ctype_le__, c_int)
else:
self.assertIs(c_int.__ctype_be__, c_int)
self.assertIs(c_int.__ctype_le__.__ctype_be__, c_int)
s = c_int.__ctype_be__(0x12345678)
self.assertEqual(bin(struct.pack(">i", 0x12345678)), "12345678")
self.assertEqual(bin(s), "12345678")
self.assertEqual(s.value, 0x12345678)
s = c_int.__ctype_le__(0x12345678)
self.assertEqual(bin(struct.pack("<i", 0x12345678)), "78563412")
self.assertEqual(bin(s), "78563412")
self.assertEqual(s.value, 0x12345678)
s = c_uint.__ctype_be__(0x12345678)
self.assertEqual(bin(struct.pack(">I", 0x12345678)), "12345678")
self.assertEqual(bin(s), "12345678")
self.assertEqual(s.value, 0x12345678)
s = c_uint.__ctype_le__(0x12345678)
self.assertEqual(bin(struct.pack("<I", 0x12345678)), "78563412")
self.assertEqual(bin(s), "78563412")
self.assertEqual(s.value, 0x12345678)
def test_endian_longlong(self):
if sys.byteorder == "little":
self.assertIs(c_longlong.__ctype_le__, c_longlong)
self.assertIs(c_longlong.__ctype_be__.__ctype_le__, c_longlong)
else:
self.assertIs(c_longlong.__ctype_be__, c_longlong)
self.assertIs(c_longlong.__ctype_le__.__ctype_be__, c_longlong)
s = c_longlong.__ctype_be__(0x1234567890ABCDEF)
self.assertEqual(bin(struct.pack(">q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
self.assertEqual(bin(s), "1234567890ABCDEF")
self.assertEqual(s.value, 0x1234567890ABCDEF)
s = c_longlong.__ctype_le__(0x1234567890ABCDEF)
self.assertEqual(bin(struct.pack("<q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
self.assertEqual(bin(s), "EFCDAB9078563412")
self.assertEqual(s.value, 0x1234567890ABCDEF)
s = c_ulonglong.__ctype_be__(0x1234567890ABCDEF)
self.assertEqual(bin(struct.pack(">Q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
self.assertEqual(bin(s), "1234567890ABCDEF")
self.assertEqual(s.value, 0x1234567890ABCDEF)
s = c_ulonglong.__ctype_le__(0x1234567890ABCDEF)
self.assertEqual(bin(struct.pack("<Q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
self.assertEqual(bin(s), "EFCDAB9078563412")
self.assertEqual(s.value, 0x1234567890ABCDEF)
def test_endian_float(self):
if sys.byteorder == "little":
self.assertIs(c_float.__ctype_le__, c_float)
self.assertIs(c_float.__ctype_be__.__ctype_le__, c_float)
else:
self.assertIs(c_float.__ctype_be__, c_float)
self.assertIs(c_float.__ctype_le__.__ctype_be__, c_float)
s = c_float(math.pi)
self.assertEqual(bin(struct.pack("f", math.pi)), bin(s))
# Hm, what's the precision of a float compared to a double?
self.assertAlmostEqual(s.value, math.pi, places=6)
s = c_float.__ctype_le__(math.pi)
self.assertAlmostEqual(s.value, math.pi, places=6)
self.assertEqual(bin(struct.pack("<f", math.pi)), bin(s))
s = c_float.__ctype_be__(math.pi)
self.assertAlmostEqual(s.value, math.pi, places=6)
self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s))
def test_endian_double(self):
if sys.byteorder == "little":
self.assertIs(c_double.__ctype_le__, c_double)
self.assertIs(c_double.__ctype_be__.__ctype_le__, c_double)
else:
self.assertIs(c_double.__ctype_be__, c_double)
self.assertIs(c_double.__ctype_le__.__ctype_be__, c_double)
s = c_double(math.pi)
self.assertEqual(s.value, math.pi)
self.assertEqual(bin(struct.pack("d", math.pi)), bin(s))
s = c_double.__ctype_le__(math.pi)
self.assertEqual(s.value, math.pi)
self.assertEqual(bin(struct.pack("<d", math.pi)), bin(s))
s = c_double.__ctype_be__(math.pi)
self.assertEqual(s.value, math.pi)
self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))
def test_endian_other(self):
self.assertIs(c_byte.__ctype_le__, c_byte)
self.assertIs(c_byte.__ctype_be__, c_byte)
self.assertIs(c_ubyte.__ctype_le__, c_ubyte)
self.assertIs(c_ubyte.__ctype_be__, c_ubyte)
self.assertIs(c_char.__ctype_le__, c_char)
self.assertIs(c_char.__ctype_be__, c_char)
def test_struct_fields_unsupported_byte_order(self):
fields = [
("a", c_ubyte),
("b", c_byte),
("c", c_short),
("d", c_ushort),
("e", c_int),
("f", c_uint),
("g", c_long),
("h", c_ulong),
("i", c_longlong),
("k", c_ulonglong),
("l", c_float),
("m", c_double),
("n", c_char),
("b1", c_byte, 3),
("b2", c_byte, 3),
("b3", c_byte, 2),
("a", c_int * 3 * 3 * 3)
]
# these fields do not support different byte order:
for typ in c_wchar, c_void_p, POINTER(c_int):
with self.assertRaises(TypeError):
class T(BigEndianStructure if sys.byteorder == "little" else LittleEndianStructure):
_fields_ = fields + [("x", typ)]
def test_struct_struct(self):
# nested structures with different byteorders
# create nested structures with given byteorders and set memory to data
for nested, data in (
(BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
(LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
):
for parent in (
BigEndianStructure,
LittleEndianStructure,
Structure,
):
class NestedStructure(nested):
_fields_ = [("x", c_uint32),
("y", c_uint32)]
class TestStructure(parent):
_fields_ = [("point", NestedStructure)]
self.assertEqual(len(data), sizeof(TestStructure))
ptr = POINTER(TestStructure)
s = cast(data, ptr)[0]
del ctypes._pointer_type_cache[TestStructure]
self.assertEqual(s.point.x, 1)
self.assertEqual(s.point.y, 2)
def test_struct_field_alignment(self):
# standard packing in struct uses no alignment.
# So, we have to align using pad bytes.
#
# Unaligned accesses will crash Python (on those platforms that
# don't allow it, like sparc solaris).
if sys.byteorder == "little":
base = BigEndianStructure
fmt = ">bxhid"
else:
base = LittleEndianStructure
fmt = "<bxhid"
class S(base):
_fields_ = [("b", c_byte),
("h", c_short),
("i", c_int),
("d", c_double)]
s1 = S(0x12, 0x1234, 0x12345678, 3.14)
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.assertEqual(bin(s1), bin(s2))
def test_unaligned_nonnative_struct_fields(self):
if sys.byteorder == "little":
base = BigEndianStructure
fmt = ">b h xi xd"
else:
base = LittleEndianStructure
fmt = "<b h xi xd"
class S(base):
_pack_ = 1
_fields_ = [("b", c_byte),
("h", c_short),
("_1", c_byte),
("i", c_int),
("_2", c_byte),
("d", c_double)]
s1 = S()
s1.b = 0x12
s1.h = 0x1234
s1.i = 0x12345678
s1.d = 3.14
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.assertEqual(bin(s1), bin(s2))
def test_unaligned_native_struct_fields(self):
if sys.byteorder == "little":
fmt = "<b h xi xd"
else:
base = LittleEndianStructure
fmt = ">b h xi xd"
class S(Structure):
_pack_ = 1
_fields_ = [("b", c_byte),
("h", c_short),
("_1", c_byte),
("i", c_int),
("_2", c_byte),
("d", c_double)]
s1 = S()
s1.b = 0x12
s1.h = 0x1234
s1.i = 0x12345678
s1.d = 3.14
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.assertEqual(bin(s1), bin(s2))
def test_union_fields_unsupported_byte_order(self):
fields = [
("a", c_ubyte),
("b", c_byte),
("c", c_short),
("d", c_ushort),
("e", c_int),
("f", c_uint),
("g", c_long),
("h", c_ulong),
("i", c_longlong),
("k", c_ulonglong),
("l", c_float),
("m", c_double),
("n", c_char),
("b1", c_byte, 3),
("b2", c_byte, 3),
("b3", c_byte, 2),
("a", c_int * 3 * 3 * 3)
]
# these fields do not support different byte order:
for typ in c_wchar, c_void_p, POINTER(c_int):
with self.assertRaises(TypeError):
class T(BigEndianUnion if sys.byteorder == "little" else LittleEndianUnion):
_fields_ = fields + [("x", typ)]
def test_union_struct(self):
# nested structures in unions with different byteorders
# create nested structures in unions with given byteorders and set memory to data
for nested, data in (
(BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
(LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
):
for parent in (
BigEndianUnion,
LittleEndianUnion,
Union,
):
class NestedStructure(nested):
_fields_ = [("x", c_uint32),
("y", c_uint32)]
class TestUnion(parent):
_fields_ = [("point", NestedStructure)]
self.assertEqual(len(data), sizeof(TestUnion))
ptr = POINTER(TestUnion)
s = cast(data, ptr)[0]
del ctypes._pointer_type_cache[TestUnion]
self.assertEqual(s.point.x, 1)
self.assertEqual(s.point.y, 2)
if __name__ == "__main__":
unittest.main()

333
Lib/ctypes/test/test_callbacks.py vendored Normal file
View File

@@ -0,0 +1,333 @@
import functools
import unittest
from test import support
from ctypes import *
from ctypes.test import need_symbol
from _ctypes import CTYPES_MAX_ARGCOUNT
import _ctypes_test
class Callbacks(unittest.TestCase):
functype = CFUNCTYPE
## def tearDown(self):
## import gc
## gc.collect()
def callback(self, *args):
self.got_args = args
return args[-1]
def check_type(self, typ, arg):
PROTO = self.functype.__func__(typ, typ)
result = PROTO(self.callback)(arg)
if typ == c_float:
self.assertAlmostEqual(result, arg, places=5)
else:
self.assertEqual(self.got_args, (arg,))
self.assertEqual(result, arg)
PROTO = self.functype.__func__(typ, c_byte, typ)
result = PROTO(self.callback)(-3, arg)
if typ == c_float:
self.assertAlmostEqual(result, arg, places=5)
else:
self.assertEqual(self.got_args, (-3, arg))
self.assertEqual(result, arg)
################
def test_byte(self):
self.check_type(c_byte, 42)
self.check_type(c_byte, -42)
def test_ubyte(self):
self.check_type(c_ubyte, 42)
def test_short(self):
self.check_type(c_short, 42)
self.check_type(c_short, -42)
def test_ushort(self):
self.check_type(c_ushort, 42)
def test_int(self):
self.check_type(c_int, 42)
self.check_type(c_int, -42)
def test_uint(self):
self.check_type(c_uint, 42)
def test_long(self):
self.check_type(c_long, 42)
self.check_type(c_long, -42)
def test_ulong(self):
self.check_type(c_ulong, 42)
@need_symbol('c_longlong')
def test_longlong(self):
self.check_type(c_longlong, 42)
self.check_type(c_longlong, -42)
@need_symbol('c_ulonglong')
def test_ulonglong(self):
self.check_type(c_ulonglong, 42)
def test_float(self):
# only almost equal: double -> float -> double
import math
self.check_type(c_float, math.e)
self.check_type(c_float, -math.e)
def test_double(self):
self.check_type(c_double, 3.14)
self.check_type(c_double, -3.14)
@need_symbol('c_longdouble')
def test_longdouble(self):
self.check_type(c_longdouble, 3.14)
self.check_type(c_longdouble, -3.14)
def test_char(self):
self.check_type(c_char, b"x")
self.check_type(c_char, b"a")
# disabled: would now (correctly) raise a RuntimeWarning about
# a memory leak. A callback function cannot return a non-integral
# C type without causing a memory leak.
@unittest.skip('test disabled')
def test_char_p(self):
self.check_type(c_char_p, "abc")
self.check_type(c_char_p, "def")
def test_pyobject(self):
o = ()
from sys import getrefcount as grc
for o in (), [], object():
initial = grc(o)
# This call leaks a reference to 'o'...
self.check_type(py_object, o)
before = grc(o)
# ...but this call doesn't leak any more. Where is the refcount?
self.check_type(py_object, o)
after = grc(o)
self.assertEqual((after, o), (before, o))
def test_unsupported_restype_1(self):
# Only "fundamental" result types are supported for callback
# functions, the type must have a non-NULL stgdict->setfunc.
# POINTER(c_double), for example, is not supported.
prototype = self.functype.__func__(POINTER(c_double))
# The type is checked when the prototype is called
self.assertRaises(TypeError, prototype, lambda: None)
def test_unsupported_restype_2(self):
prototype = self.functype.__func__(object)
self.assertRaises(TypeError, prototype, lambda: None)
def test_issue_7959(self):
proto = self.functype.__func__(None)
class X(object):
def func(self): pass
def __init__(self):
self.v = proto(self.func)
import gc
for i in range(32):
X()
gc.collect()
live = [x for x in gc.get_objects()
if isinstance(x, X)]
self.assertEqual(len(live), 0)
def test_issue12483(self):
import gc
class Nasty:
def __del__(self):
gc.collect()
CFUNCTYPE(None)(lambda x=Nasty(): None)
@need_symbol('WINFUNCTYPE')
class StdcallCallbacks(Callbacks):
try:
functype = WINFUNCTYPE
except NameError:
pass
################################################################
class SampleCallbacksTestCase(unittest.TestCase):
def test_integrate(self):
# Derived from some then non-working code, posted by David Foster
dll = CDLL(_ctypes_test.__file__)
# The function prototype called by 'integrate': double func(double);
CALLBACK = CFUNCTYPE(c_double, c_double)
# The integrate function itself, exposed from the _ctypes_test dll
integrate = dll.integrate
integrate.argtypes = (c_double, c_double, CALLBACK, c_long)
integrate.restype = c_double
def func(x):
return x**2
result = integrate(0.0, 1.0, CALLBACK(func), 10)
diff = abs(result - 1./3.)
self.assertLess(diff, 0.01, "%s not less than 0.01" % diff)
def test_issue_8959_a(self):
from ctypes.util import find_library
libc_path = find_library("c")
if not libc_path:
self.skipTest('could not find libc')
libc = CDLL(libc_path)
@CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
def cmp_func(a, b):
return a[0] - b[0]
array = (c_int * 5)(5, 1, 99, 7, 33)
libc.qsort(array, len(array), sizeof(c_int), cmp_func)
self.assertEqual(array[:], [1, 5, 7, 33, 99])
@need_symbol('WINFUNCTYPE')
def test_issue_8959_b(self):
from ctypes.wintypes import BOOL, HWND, LPARAM
global windowCount
windowCount = 0
@WINFUNCTYPE(BOOL, HWND, LPARAM)
def EnumWindowsCallbackFunc(hwnd, lParam):
global windowCount
windowCount += 1
return True #Allow windows to keep enumerating
windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0)
def test_callback_register_int(self):
# Issue #8275: buggy handling of callback args under Win64
# NOTE: should be run on release builds as well
dll = CDLL(_ctypes_test.__file__)
CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int)
# All this function does is call the callback with its args squared
func = dll._testfunc_cbk_reg_int
func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK)
func.restype = c_int
def callback(a, b, c, d, e):
return a + b + c + d + e
result = func(2, 3, 4, 5, 6, CALLBACK(callback))
self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6))
def test_callback_register_double(self):
# Issue #8275: buggy handling of callback args under Win64
# NOTE: should be run on release builds as well
dll = CDLL(_ctypes_test.__file__)
CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double,
c_double, c_double)
# All this function does is call the callback with its args squared
func = dll._testfunc_cbk_reg_double
func.argtypes = (c_double, c_double, c_double,
c_double, c_double, CALLBACK)
func.restype = c_double
def callback(a, b, c, d, e):
return a + b + c + d + e
result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback))
self.assertEqual(result,
callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
def test_callback_large_struct(self):
class Check: pass
# This should mirror the structure in Modules/_ctypes/_ctypes_test.c
class X(Structure):
_fields_ = [
('first', c_ulong),
('second', c_ulong),
('third', c_ulong),
]
def callback(check, s):
check.first = s.first
check.second = s.second
check.third = s.third
# See issue #29565.
# The structure should be passed by value, so
# any changes to it should not be reflected in
# the value passed
s.first = s.second = s.third = 0x0badf00d
check = Check()
s = X()
s.first = 0xdeadbeef
s.second = 0xcafebabe
s.third = 0x0bad1dea
CALLBACK = CFUNCTYPE(None, X)
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_cbk_large_struct
func.argtypes = (X, CALLBACK)
func.restype = None
# the function just calls the callback with the passed structure
func(s, CALLBACK(functools.partial(callback, check)))
self.assertEqual(check.first, s.first)
self.assertEqual(check.second, s.second)
self.assertEqual(check.third, s.third)
self.assertEqual(check.first, 0xdeadbeef)
self.assertEqual(check.second, 0xcafebabe)
self.assertEqual(check.third, 0x0bad1dea)
# See issue #29565.
# Ensure that the original struct is unchanged.
self.assertEqual(s.first, check.first)
self.assertEqual(s.second, check.second)
self.assertEqual(s.third, check.third)
def test_callback_too_many_args(self):
def func(*args):
return len(args)
# valid call with nargs <= CTYPES_MAX_ARGCOUNT
proto = CFUNCTYPE(c_int, *(c_int,) * CTYPES_MAX_ARGCOUNT)
cb = proto(func)
args1 = (1,) * CTYPES_MAX_ARGCOUNT
self.assertEqual(cb(*args1), CTYPES_MAX_ARGCOUNT)
# invalid call with nargs > CTYPES_MAX_ARGCOUNT
args2 = (1,) * (CTYPES_MAX_ARGCOUNT + 1)
with self.assertRaises(ArgumentError):
cb(*args2)
# error when creating the type with too many arguments
with self.assertRaises(ArgumentError):
CFUNCTYPE(c_int, *(c_int,) * (CTYPES_MAX_ARGCOUNT + 1))
def test_convert_result_error(self):
def func():
return ("tuple",)
proto = CFUNCTYPE(c_int)
ctypes_func = proto(func)
with support.catch_unraisable_exception() as cm:
# don't test the result since it is an uninitialized value
result = ctypes_func()
self.assertIsInstance(cm.unraisable.exc_value, TypeError)
self.assertEqual(cm.unraisable.err_msg,
"Exception ignored on converting result "
"of ctypes callback function")
self.assertIs(cm.unraisable.object, func)
if __name__ == '__main__':
unittest.main()

99
Lib/ctypes/test/test_cast.py vendored Normal file
View File

@@ -0,0 +1,99 @@
from ctypes import *
from ctypes.test import need_symbol
import unittest
import sys
class Test(unittest.TestCase):
def test_array2pointer(self):
array = (c_int * 3)(42, 17, 2)
# casting an array to a pointer works.
ptr = cast(array, POINTER(c_int))
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
if 2*sizeof(c_short) == sizeof(c_int):
ptr = cast(array, POINTER(c_short))
if sys.byteorder == "little":
self.assertEqual([ptr[i] for i in range(6)],
[42, 0, 17, 0, 2, 0])
else:
self.assertEqual([ptr[i] for i in range(6)],
[0, 42, 0, 17, 0, 2])
def test_address2pointer(self):
array = (c_int * 3)(42, 17, 2)
address = addressof(array)
ptr = cast(c_void_p(address), POINTER(c_int))
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
ptr = cast(address, POINTER(c_int))
self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2])
def test_p2a_objects(self):
array = (c_char_p * 5)()
self.assertEqual(array._objects, None)
array[0] = b"foo bar"
self.assertEqual(array._objects, {'0': b"foo bar"})
p = cast(array, POINTER(c_char_p))
# array and p share a common _objects attribute
self.assertIs(p._objects, array._objects)
self.assertEqual(array._objects, {'0': b"foo bar", id(array): array})
p[0] = b"spam spam"
self.assertEqual(p._objects, {'0': b"spam spam", id(array): array})
self.assertIs(array._objects, p._objects)
p[1] = b"foo bar"
self.assertEqual(p._objects, {'1': b'foo bar', '0': b"spam spam", id(array): array})
self.assertIs(array._objects, p._objects)
def test_other(self):
p = cast((c_int * 4)(1, 2, 3, 4), POINTER(c_int))
self.assertEqual(p[:4], [1,2, 3, 4])
self.assertEqual(p[:4:], [1, 2, 3, 4])
self.assertEqual(p[3:-1:-1], [4, 3, 2, 1])
self.assertEqual(p[:4:3], [1, 4])
c_int()
self.assertEqual(p[:4], [1, 2, 3, 4])
self.assertEqual(p[:4:], [1, 2, 3, 4])
self.assertEqual(p[3:-1:-1], [4, 3, 2, 1])
self.assertEqual(p[:4:3], [1, 4])
p[2] = 96
self.assertEqual(p[:4], [1, 2, 96, 4])
self.assertEqual(p[:4:], [1, 2, 96, 4])
self.assertEqual(p[3:-1:-1], [4, 96, 2, 1])
self.assertEqual(p[:4:3], [1, 4])
c_int()
self.assertEqual(p[:4], [1, 2, 96, 4])
self.assertEqual(p[:4:], [1, 2, 96, 4])
self.assertEqual(p[3:-1:-1], [4, 96, 2, 1])
self.assertEqual(p[:4:3], [1, 4])
def test_char_p(self):
# This didn't work: bad argument to internal function
s = c_char_p(b"hiho")
self.assertEqual(cast(cast(s, c_void_p), c_char_p).value,
b"hiho")
@need_symbol('c_wchar_p')
def test_wchar_p(self):
s = c_wchar_p("hiho")
self.assertEqual(cast(cast(s, c_void_p), c_wchar_p).value,
"hiho")
def test_bad_type_arg(self):
# The type argument must be a ctypes pointer type.
array_type = c_byte * sizeof(c_int)
array = array_type()
self.assertRaises(TypeError, cast, array, None)
self.assertRaises(TypeError, cast, array, array_type)
class Struct(Structure):
_fields_ = [("a", c_int)]
self.assertRaises(TypeError, cast, array, Struct)
class MyUnion(Union):
_fields_ = [("a", c_int)]
self.assertRaises(TypeError, cast, array, MyUnion)
if __name__ == "__main__":
unittest.main()

218
Lib/ctypes/test/test_cfuncs.py vendored Normal file
View File

@@ -0,0 +1,218 @@
# A lot of failures in these tests on Mac OS X.
# Byte order related?
import unittest
from ctypes import *
from ctypes.test import need_symbol
import _ctypes_test
class CFunctions(unittest.TestCase):
_dll = CDLL(_ctypes_test.__file__)
def S(self):
return c_longlong.in_dll(self._dll, "last_tf_arg_s").value
def U(self):
return c_ulonglong.in_dll(self._dll, "last_tf_arg_u").value
def test_byte(self):
self._dll.tf_b.restype = c_byte
self._dll.tf_b.argtypes = (c_byte,)
self.assertEqual(self._dll.tf_b(-126), -42)
self.assertEqual(self.S(), -126)
def test_byte_plus(self):
self._dll.tf_bb.restype = c_byte
self._dll.tf_bb.argtypes = (c_byte, c_byte)
self.assertEqual(self._dll.tf_bb(0, -126), -42)
self.assertEqual(self.S(), -126)
def test_ubyte(self):
self._dll.tf_B.restype = c_ubyte
self._dll.tf_B.argtypes = (c_ubyte,)
self.assertEqual(self._dll.tf_B(255), 85)
self.assertEqual(self.U(), 255)
def test_ubyte_plus(self):
self._dll.tf_bB.restype = c_ubyte
self._dll.tf_bB.argtypes = (c_byte, c_ubyte)
self.assertEqual(self._dll.tf_bB(0, 255), 85)
self.assertEqual(self.U(), 255)
def test_short(self):
self._dll.tf_h.restype = c_short
self._dll.tf_h.argtypes = (c_short,)
self.assertEqual(self._dll.tf_h(-32766), -10922)
self.assertEqual(self.S(), -32766)
def test_short_plus(self):
self._dll.tf_bh.restype = c_short
self._dll.tf_bh.argtypes = (c_byte, c_short)
self.assertEqual(self._dll.tf_bh(0, -32766), -10922)
self.assertEqual(self.S(), -32766)
def test_ushort(self):
self._dll.tf_H.restype = c_ushort
self._dll.tf_H.argtypes = (c_ushort,)
self.assertEqual(self._dll.tf_H(65535), 21845)
self.assertEqual(self.U(), 65535)
def test_ushort_plus(self):
self._dll.tf_bH.restype = c_ushort
self._dll.tf_bH.argtypes = (c_byte, c_ushort)
self.assertEqual(self._dll.tf_bH(0, 65535), 21845)
self.assertEqual(self.U(), 65535)
def test_int(self):
self._dll.tf_i.restype = c_int
self._dll.tf_i.argtypes = (c_int,)
self.assertEqual(self._dll.tf_i(-2147483646), -715827882)
self.assertEqual(self.S(), -2147483646)
def test_int_plus(self):
self._dll.tf_bi.restype = c_int
self._dll.tf_bi.argtypes = (c_byte, c_int)
self.assertEqual(self._dll.tf_bi(0, -2147483646), -715827882)
self.assertEqual(self.S(), -2147483646)
def test_uint(self):
self._dll.tf_I.restype = c_uint
self._dll.tf_I.argtypes = (c_uint,)
self.assertEqual(self._dll.tf_I(4294967295), 1431655765)
self.assertEqual(self.U(), 4294967295)
def test_uint_plus(self):
self._dll.tf_bI.restype = c_uint
self._dll.tf_bI.argtypes = (c_byte, c_uint)
self.assertEqual(self._dll.tf_bI(0, 4294967295), 1431655765)
self.assertEqual(self.U(), 4294967295)
def test_long(self):
self._dll.tf_l.restype = c_long
self._dll.tf_l.argtypes = (c_long,)
self.assertEqual(self._dll.tf_l(-2147483646), -715827882)
self.assertEqual(self.S(), -2147483646)
def test_long_plus(self):
self._dll.tf_bl.restype = c_long
self._dll.tf_bl.argtypes = (c_byte, c_long)
self.assertEqual(self._dll.tf_bl(0, -2147483646), -715827882)
self.assertEqual(self.S(), -2147483646)
def test_ulong(self):
self._dll.tf_L.restype = c_ulong
self._dll.tf_L.argtypes = (c_ulong,)
self.assertEqual(self._dll.tf_L(4294967295), 1431655765)
self.assertEqual(self.U(), 4294967295)
def test_ulong_plus(self):
self._dll.tf_bL.restype = c_ulong
self._dll.tf_bL.argtypes = (c_char, c_ulong)
self.assertEqual(self._dll.tf_bL(b' ', 4294967295), 1431655765)
self.assertEqual(self.U(), 4294967295)
@need_symbol('c_longlong')
def test_longlong(self):
self._dll.tf_q.restype = c_longlong
self._dll.tf_q.argtypes = (c_longlong, )
self.assertEqual(self._dll.tf_q(-9223372036854775806), -3074457345618258602)
self.assertEqual(self.S(), -9223372036854775806)
@need_symbol('c_longlong')
def test_longlong_plus(self):
self._dll.tf_bq.restype = c_longlong
self._dll.tf_bq.argtypes = (c_byte, c_longlong)
self.assertEqual(self._dll.tf_bq(0, -9223372036854775806), -3074457345618258602)
self.assertEqual(self.S(), -9223372036854775806)
@need_symbol('c_ulonglong')
def test_ulonglong(self):
self._dll.tf_Q.restype = c_ulonglong
self._dll.tf_Q.argtypes = (c_ulonglong, )
self.assertEqual(self._dll.tf_Q(18446744073709551615), 6148914691236517205)
self.assertEqual(self.U(), 18446744073709551615)
@need_symbol('c_ulonglong')
def test_ulonglong_plus(self):
self._dll.tf_bQ.restype = c_ulonglong
self._dll.tf_bQ.argtypes = (c_byte, c_ulonglong)
self.assertEqual(self._dll.tf_bQ(0, 18446744073709551615), 6148914691236517205)
self.assertEqual(self.U(), 18446744073709551615)
def test_float(self):
self._dll.tf_f.restype = c_float
self._dll.tf_f.argtypes = (c_float,)
self.assertEqual(self._dll.tf_f(-42.), -14.)
self.assertEqual(self.S(), -42)
def test_float_plus(self):
self._dll.tf_bf.restype = c_float
self._dll.tf_bf.argtypes = (c_byte, c_float)
self.assertEqual(self._dll.tf_bf(0, -42.), -14.)
self.assertEqual(self.S(), -42)
def test_double(self):
self._dll.tf_d.restype = c_double
self._dll.tf_d.argtypes = (c_double,)
self.assertEqual(self._dll.tf_d(42.), 14.)
self.assertEqual(self.S(), 42)
def test_double_plus(self):
self._dll.tf_bd.restype = c_double
self._dll.tf_bd.argtypes = (c_byte, c_double)
self.assertEqual(self._dll.tf_bd(0, 42.), 14.)
self.assertEqual(self.S(), 42)
@need_symbol('c_longdouble')
def test_longdouble(self):
self._dll.tf_D.restype = c_longdouble
self._dll.tf_D.argtypes = (c_longdouble,)
self.assertEqual(self._dll.tf_D(42.), 14.)
self.assertEqual(self.S(), 42)
@need_symbol('c_longdouble')
def test_longdouble_plus(self):
self._dll.tf_bD.restype = c_longdouble
self._dll.tf_bD.argtypes = (c_byte, c_longdouble)
self.assertEqual(self._dll.tf_bD(0, 42.), 14.)
self.assertEqual(self.S(), 42)
def test_callwithresult(self):
def process_result(result):
return result * 2
self._dll.tf_i.restype = process_result
self._dll.tf_i.argtypes = (c_int,)
self.assertEqual(self._dll.tf_i(42), 28)
self.assertEqual(self.S(), 42)
self.assertEqual(self._dll.tf_i(-42), -28)
self.assertEqual(self.S(), -42)
def test_void(self):
self._dll.tv_i.restype = None
self._dll.tv_i.argtypes = (c_int,)
self.assertEqual(self._dll.tv_i(42), None)
self.assertEqual(self.S(), 42)
self.assertEqual(self._dll.tv_i(-42), None)
self.assertEqual(self.S(), -42)
# The following repeats the above tests with stdcall functions (where
# they are available)
try:
WinDLL
except NameError:
def stdcall_dll(*_): pass
else:
class stdcall_dll(WinDLL):
def __getattr__(self, name):
if name[:2] == '__' and name[-2:] == '__':
raise AttributeError(name)
func = self._FuncPtr(("s_" + name, self))
setattr(self, name, func)
return func
@need_symbol('WinDLL')
class stdcallCFunctions(CFunctions):
_dll = stdcall_dll(_ctypes_test.__file__)
if __name__ == '__main__':
unittest.main()

36
Lib/ctypes/test/test_checkretval.py vendored Normal file
View File

@@ -0,0 +1,36 @@
import unittest
from ctypes import *
from ctypes.test import need_symbol
class CHECKED(c_int):
def _check_retval_(value):
# Receives a CHECKED instance.
return str(value.value)
_check_retval_ = staticmethod(_check_retval_)
class Test(unittest.TestCase):
def test_checkretval(self):
import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
self.assertEqual(42, dll._testfunc_p_p(42))
dll._testfunc_p_p.restype = CHECKED
self.assertEqual("42", dll._testfunc_p_p(42))
dll._testfunc_p_p.restype = None
self.assertEqual(None, dll._testfunc_p_p(42))
del dll._testfunc_p_p.restype
self.assertEqual(42, dll._testfunc_p_p(42))
@need_symbol('oledll')
def test_oledll(self):
self.assertRaises(OSError,
oledll.oleaut32.CreateTypeLib2,
0, None, None)
if __name__ == "__main__":
unittest.main()

21
Lib/ctypes/test/test_delattr.py vendored Normal file
View File

@@ -0,0 +1,21 @@
import unittest
from ctypes import *
class X(Structure):
_fields_ = [("foo", c_int)]
class TestCase(unittest.TestCase):
def test_simple(self):
self.assertRaises(TypeError,
delattr, c_int(42), "value")
def test_chararray(self):
self.assertRaises(TypeError,
delattr, (c_char * 5)(), "value")
def test_struct(self):
self.assertRaises(TypeError,
delattr, X(), "foo")
if __name__ == "__main__":
unittest.main()

76
Lib/ctypes/test/test_errno.py vendored Normal file
View File

@@ -0,0 +1,76 @@
import unittest, os, errno
import threading
from ctypes import *
from ctypes.util import find_library
class Test(unittest.TestCase):
def test_open(self):
libc_name = find_library("c")
if libc_name is None:
raise unittest.SkipTest("Unable to find C library")
libc = CDLL(libc_name, use_errno=True)
if os.name == "nt":
libc_open = libc._open
else:
libc_open = libc.open
libc_open.argtypes = c_char_p, c_int
self.assertEqual(libc_open(b"", 0), -1)
self.assertEqual(get_errno(), errno.ENOENT)
self.assertEqual(set_errno(32), errno.ENOENT)
self.assertEqual(get_errno(), 32)
def _worker():
set_errno(0)
libc = CDLL(libc_name, use_errno=False)
if os.name == "nt":
libc_open = libc._open
else:
libc_open = libc.open
libc_open.argtypes = c_char_p, c_int
self.assertEqual(libc_open(b"", 0), -1)
self.assertEqual(get_errno(), 0)
t = threading.Thread(target=_worker)
t.start()
t.join()
self.assertEqual(get_errno(), 32)
set_errno(0)
@unittest.skipUnless(os.name == "nt", 'Test specific to Windows')
def test_GetLastError(self):
dll = WinDLL("kernel32", use_last_error=True)
GetModuleHandle = dll.GetModuleHandleA
GetModuleHandle.argtypes = [c_wchar_p]
self.assertEqual(0, GetModuleHandle("foo"))
self.assertEqual(get_last_error(), 126)
self.assertEqual(set_last_error(32), 126)
self.assertEqual(get_last_error(), 32)
def _worker():
set_last_error(0)
dll = WinDLL("kernel32", use_last_error=False)
GetModuleHandle = dll.GetModuleHandleW
GetModuleHandle.argtypes = [c_wchar_p]
GetModuleHandle("bar")
self.assertEqual(get_last_error(), 0)
t = threading.Thread(target=_worker)
t.start()
t.join()
self.assertEqual(get_last_error(), 32)
set_last_error(0)
if __name__ == "__main__":
unittest.main()

127
Lib/ctypes/test/test_find.py vendored Normal file
View File

@@ -0,0 +1,127 @@
import unittest
import unittest.mock
import os.path
import sys
import test.support
from test.support import os_helper
from ctypes import *
from ctypes.util import find_library
# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
class Test_OpenGL_libs(unittest.TestCase):
@classmethod
def setUpClass(cls):
lib_gl = lib_glu = lib_gle = None
if sys.platform == "win32":
lib_gl = find_library("OpenGL32")
lib_glu = find_library("Glu32")
elif sys.platform == "darwin":
lib_gl = lib_glu = find_library("OpenGL")
else:
lib_gl = find_library("GL")
lib_glu = find_library("GLU")
lib_gle = find_library("gle")
## print, for debugging
if test.support.verbose:
print("OpenGL libraries:")
for item in (("GL", lib_gl),
("GLU", lib_glu),
("gle", lib_gle)):
print("\t", item)
cls.gl = cls.glu = cls.gle = None
if lib_gl:
try:
cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
except OSError:
pass
if lib_glu:
try:
cls.glu = CDLL(lib_glu, RTLD_GLOBAL)
except OSError:
pass
if lib_gle:
try:
cls.gle = CDLL(lib_gle)
except OSError:
pass
@classmethod
def tearDownClass(cls):
cls.gl = cls.glu = cls.gle = None
def test_gl(self):
if self.gl is None:
self.skipTest('lib_gl not available')
self.gl.glClearIndex
def test_glu(self):
if self.glu is None:
self.skipTest('lib_glu not available')
self.glu.gluBeginCurve
def test_gle(self):
if self.gle is None:
self.skipTest('lib_gle not available')
self.gle.gleGetJoinStyle
def test_shell_injection(self):
result = find_library('; echo Hello shell > ' + os_helper.TESTFN)
self.assertFalse(os.path.lexists(os_helper.TESTFN))
self.assertIsNone(result)
@unittest.skipUnless(sys.platform.startswith('linux'),
'Test only valid for Linux')
class FindLibraryLinux(unittest.TestCase):
def test_find_on_libpath(self):
import subprocess
import tempfile
try:
p = subprocess.Popen(['gcc', '--version'], stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL)
out, _ = p.communicate()
except OSError:
raise unittest.SkipTest('gcc, needed for test, not available')
with tempfile.TemporaryDirectory() as d:
# create an empty temporary file
srcname = os.path.join(d, 'dummy.c')
libname = 'py_ctypes_test_dummy'
dstname = os.path.join(d, 'lib%s.so' % libname)
with open(srcname, 'wb') as f:
pass
self.assertTrue(os.path.exists(srcname))
# compile the file to a shared library
cmd = ['gcc', '-o', dstname, '--shared',
'-Wl,-soname,lib%s.so' % libname, srcname]
out = subprocess.check_output(cmd)
self.assertTrue(os.path.exists(dstname))
# now check that the .so can't be found (since not in
# LD_LIBRARY_PATH)
self.assertIsNone(find_library(libname))
# now add the location to LD_LIBRARY_PATH
with os_helper.EnvironmentVarGuard() as env:
KEY = 'LD_LIBRARY_PATH'
if KEY not in env:
v = d
else:
v = '%s:%s' % (env[KEY], d)
env.set(KEY, v)
# now check that the .so can be found (since in
# LD_LIBRARY_PATH)
self.assertEqual(find_library(libname), 'lib%s.so' % libname)
def test_find_library_with_gcc(self):
with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
self.assertNotEqual(find_library('c'), None)
def test_find_library_with_ld(self):
with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
self.assertNotEqual(find_library('c'), None)
if __name__ == "__main__":
unittest.main()

141
Lib/ctypes/test/test_frombuffer.py vendored Normal file
View File

@@ -0,0 +1,141 @@
from ctypes import *
import array
import gc
import unittest
class X(Structure):
_fields_ = [("c_int", c_int)]
init_called = False
def __init__(self):
self._init_called = True
class Test(unittest.TestCase):
def test_from_buffer(self):
a = array.array("i", range(16))
x = (c_int * 16).from_buffer(a)
y = X.from_buffer(a)
self.assertEqual(y.c_int, a[0])
self.assertFalse(y.init_called)
self.assertEqual(x[:], a.tolist())
a[0], a[-1] = 200, -200
self.assertEqual(x[:], a.tolist())
self.assertRaises(BufferError, a.append, 100)
self.assertRaises(BufferError, a.pop)
del x; del y; gc.collect(); gc.collect(); gc.collect()
a.append(100)
a.pop()
x = (c_int * 16).from_buffer(a)
self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj
for obj in x._objects.values()])
expected = x[:]
del a; gc.collect(); gc.collect(); gc.collect()
self.assertEqual(x[:], expected)
with self.assertRaisesRegex(TypeError, "not writable"):
(c_char * 16).from_buffer(b"a" * 16)
with self.assertRaisesRegex(TypeError, "not writable"):
(c_char * 16).from_buffer(memoryview(b"a" * 16))
with self.assertRaisesRegex(TypeError, "not C contiguous"):
(c_char * 16).from_buffer(memoryview(bytearray(b"a" * 16))[::-1])
msg = "bytes-like object is required"
with self.assertRaisesRegex(TypeError, msg):
(c_char * 16).from_buffer("a" * 16)
def test_fortran_contiguous(self):
try:
import _testbuffer
except ImportError as err:
self.skipTest(str(err))
flags = _testbuffer.ND_WRITABLE | _testbuffer.ND_FORTRAN
array = _testbuffer.ndarray(
[97] * 16, format="B", shape=[4, 4], flags=flags)
with self.assertRaisesRegex(TypeError, "not C contiguous"):
(c_char * 16).from_buffer(array)
array = memoryview(array)
self.assertTrue(array.f_contiguous)
self.assertFalse(array.c_contiguous)
with self.assertRaisesRegex(TypeError, "not C contiguous"):
(c_char * 16).from_buffer(array)
def test_from_buffer_with_offset(self):
a = array.array("i", range(16))
x = (c_int * 15).from_buffer(a, sizeof(c_int))
self.assertEqual(x[:], a.tolist()[1:])
with self.assertRaises(ValueError):
c_int.from_buffer(a, -1)
with self.assertRaises(ValueError):
(c_int * 16).from_buffer(a, sizeof(c_int))
with self.assertRaises(ValueError):
(c_int * 1).from_buffer(a, 16 * sizeof(c_int))
def test_from_buffer_memoryview(self):
a = [c_char.from_buffer(memoryview(bytearray(b'a')))]
a.append(a)
del a
gc.collect() # Should not crash
def test_from_buffer_copy(self):
a = array.array("i", range(16))
x = (c_int * 16).from_buffer_copy(a)
y = X.from_buffer_copy(a)
self.assertEqual(y.c_int, a[0])
self.assertFalse(y.init_called)
self.assertEqual(x[:], list(range(16)))
a[0], a[-1] = 200, -200
self.assertEqual(x[:], list(range(16)))
a.append(100)
self.assertEqual(x[:], list(range(16)))
self.assertEqual(x._objects, None)
del a; gc.collect(); gc.collect(); gc.collect()
self.assertEqual(x[:], list(range(16)))
x = (c_char * 16).from_buffer_copy(b"a" * 16)
self.assertEqual(x[:], b"a" * 16)
with self.assertRaises(TypeError):
(c_char * 16).from_buffer_copy("a" * 16)
def test_from_buffer_copy_with_offset(self):
a = array.array("i", range(16))
x = (c_int * 15).from_buffer_copy(a, sizeof(c_int))
self.assertEqual(x[:], a.tolist()[1:])
with self.assertRaises(ValueError):
c_int.from_buffer_copy(a, -1)
with self.assertRaises(ValueError):
(c_int * 16).from_buffer_copy(a, sizeof(c_int))
with self.assertRaises(ValueError):
(c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int))
def test_abstract(self):
from ctypes import _Pointer, _SimpleCData, _CFuncPtr
self.assertRaises(TypeError, Array.from_buffer, bytearray(10))
self.assertRaises(TypeError, Structure.from_buffer, bytearray(10))
self.assertRaises(TypeError, Union.from_buffer, bytearray(10))
self.assertRaises(TypeError, _CFuncPtr.from_buffer, bytearray(10))
self.assertRaises(TypeError, _Pointer.from_buffer, bytearray(10))
self.assertRaises(TypeError, _SimpleCData.from_buffer, bytearray(10))
self.assertRaises(TypeError, Array.from_buffer_copy, b"123")
self.assertRaises(TypeError, Structure.from_buffer_copy, b"123")
self.assertRaises(TypeError, Union.from_buffer_copy, b"123")
self.assertRaises(TypeError, _CFuncPtr.from_buffer_copy, b"123")
self.assertRaises(TypeError, _Pointer.from_buffer_copy, b"123")
self.assertRaises(TypeError, _SimpleCData.from_buffer_copy, b"123")
if __name__ == '__main__':
unittest.main()

132
Lib/ctypes/test/test_funcptr.py vendored Normal file
View File

@@ -0,0 +1,132 @@
import unittest
from ctypes import *
try:
WINFUNCTYPE
except NameError:
# fake to enable this test on Linux
WINFUNCTYPE = CFUNCTYPE
import _ctypes_test
lib = CDLL(_ctypes_test.__file__)
class CFuncPtrTestCase(unittest.TestCase):
def test_basic(self):
X = WINFUNCTYPE(c_int, c_int, c_int)
def func(*args):
return len(args)
x = X(func)
self.assertEqual(x.restype, c_int)
self.assertEqual(x.argtypes, (c_int, c_int))
self.assertEqual(sizeof(x), sizeof(c_voidp))
self.assertEqual(sizeof(X), sizeof(c_voidp))
def test_first(self):
StdCallback = WINFUNCTYPE(c_int, c_int, c_int)
CdeclCallback = CFUNCTYPE(c_int, c_int, c_int)
def func(a, b):
return a + b
s = StdCallback(func)
c = CdeclCallback(func)
self.assertEqual(s(1, 2), 3)
self.assertEqual(c(1, 2), 3)
# The following no longer raises a TypeError - it is now
# possible, as in C, to call cdecl functions with more parameters.
#self.assertRaises(TypeError, c, 1, 2, 3)
self.assertEqual(c(1, 2, 3, 4, 5, 6), 3)
if not WINFUNCTYPE is CFUNCTYPE:
self.assertRaises(TypeError, s, 1, 2, 3)
def test_structures(self):
WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
def wndproc(hwnd, msg, wParam, lParam):
return hwnd + msg + wParam + lParam
HINSTANCE = c_int
HICON = c_int
HCURSOR = c_int
LPCTSTR = c_char_p
class WNDCLASS(Structure):
_fields_ = [("style", c_uint),
("lpfnWndProc", WNDPROC),
("cbClsExtra", c_int),
("cbWndExtra", c_int),
("hInstance", HINSTANCE),
("hIcon", HICON),
("hCursor", HCURSOR),
("lpszMenuName", LPCTSTR),
("lpszClassName", LPCTSTR)]
wndclass = WNDCLASS()
wndclass.lpfnWndProc = WNDPROC(wndproc)
WNDPROC_2 = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
# This is no longer true, now that WINFUNCTYPE caches created types internally.
## # CFuncPtr subclasses are compared by identity, so this raises a TypeError:
## self.assertRaises(TypeError, setattr, wndclass,
## "lpfnWndProc", WNDPROC_2(wndproc))
# instead:
self.assertIs(WNDPROC, WNDPROC_2)
# 'wndclass.lpfnWndProc' leaks 94 references. Why?
self.assertEqual(wndclass.lpfnWndProc(1, 2, 3, 4), 10)
f = wndclass.lpfnWndProc
del wndclass
del wndproc
self.assertEqual(f(10, 11, 12, 13), 46)
def test_dllfunctions(self):
def NoNullHandle(value):
if not value:
raise WinError()
return value
strchr = lib.my_strchr
strchr.restype = c_char_p
strchr.argtypes = (c_char_p, c_char)
self.assertEqual(strchr(b"abcdefghi", b"b"), b"bcdefghi")
self.assertEqual(strchr(b"abcdefghi", b"x"), None)
strtok = lib.my_strtok
strtok.restype = c_char_p
# Neither of this does work: strtok changes the buffer it is passed
## strtok.argtypes = (c_char_p, c_char_p)
## strtok.argtypes = (c_string, c_char_p)
def c_string(init):
size = len(init) + 1
return (c_char*size)(*init)
s = b"a\nb\nc"
b = c_string(s)
## b = (c_char * (len(s)+1))()
## b.value = s
## b = c_string(s)
self.assertEqual(strtok(b, b"\n"), b"a")
self.assertEqual(strtok(None, b"\n"), b"b")
self.assertEqual(strtok(None, b"\n"), b"c")
self.assertEqual(strtok(None, b"\n"), None)
def test_abstract(self):
from ctypes import _CFuncPtr
self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid")
if __name__ == '__main__':
unittest.main()

384
Lib/ctypes/test/test_functions.py vendored Normal file
View File

@@ -0,0 +1,384 @@
"""
Here is probably the place to write the docs, since the test-cases
show how the type behave.
Later...
"""
from ctypes import *
from ctypes.test import need_symbol
import sys, unittest
try:
WINFUNCTYPE
except NameError:
# fake to enable this test on Linux
WINFUNCTYPE = CFUNCTYPE
import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
if sys.platform == "win32":
windll = WinDLL(_ctypes_test.__file__)
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
class RECT(Structure):
_fields_ = [("left", c_int), ("top", c_int),
("right", c_int), ("bottom", c_int)]
class FunctionTestCase(unittest.TestCase):
def test_mro(self):
# in Python 2.3, this raises TypeError: MRO conflict among bases classes,
# in Python 2.2 it works.
#
# But in early versions of _ctypes.c, the result of tp_new
# wasn't checked, and it even crashed Python.
# Found by Greg Chapman.
with self.assertRaises(TypeError):
class X(object, Array):
_length_ = 5
_type_ = "i"
from _ctypes import _Pointer
with self.assertRaises(TypeError):
class X(object, _Pointer):
pass
from _ctypes import _SimpleCData
with self.assertRaises(TypeError):
class X(object, _SimpleCData):
_type_ = "i"
with self.assertRaises(TypeError):
class X(object, Structure):
_fields_ = []
@need_symbol('c_wchar')
def test_wchar_parm(self):
f = dll._testfunc_i_bhilfd
f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
result = f(1, "x", 3, 4, 5.0, 6.0)
self.assertEqual(result, 139)
self.assertEqual(type(result), int)
@need_symbol('c_wchar')
def test_wchar_result(self):
f = dll._testfunc_i_bhilfd
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
f.restype = c_wchar
result = f(0, 0, 0, 0, 0, 0)
self.assertEqual(result, '\x00')
def test_voidresult(self):
f = dll._testfunc_v
f.restype = None
f.argtypes = [c_int, c_int, POINTER(c_int)]
result = c_int()
self.assertEqual(None, f(1, 2, byref(result)))
self.assertEqual(result.value, 3)
def test_intresult(self):
f = dll._testfunc_i_bhilfd
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
f.restype = c_int
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), int)
result = f(-1, -2, -3, -4, -5.0, -6.0)
self.assertEqual(result, -21)
self.assertEqual(type(result), int)
# If we declare the function to return a short,
# is the high part split off?
f.restype = c_short
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), int)
result = f(1, 2, 3, 0x10004, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), int)
# You cannot assign character format codes as restype any longer
self.assertRaises(TypeError, setattr, f, "restype", "i")
def test_floatresult(self):
f = dll._testfunc_f_bhilfd
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
f.restype = c_float
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), float)
result = f(-1, -2, -3, -4, -5.0, -6.0)
self.assertEqual(result, -21)
self.assertEqual(type(result), float)
def test_doubleresult(self):
f = dll._testfunc_d_bhilfd
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
f.restype = c_double
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), float)
result = f(-1, -2, -3, -4, -5.0, -6.0)
self.assertEqual(result, -21)
self.assertEqual(type(result), float)
@need_symbol('c_longdouble')
def test_longdoubleresult(self):
f = dll._testfunc_D_bhilfD
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble]
f.restype = c_longdouble
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
self.assertEqual(type(result), float)
result = f(-1, -2, -3, -4, -5.0, -6.0)
self.assertEqual(result, -21)
self.assertEqual(type(result), float)
@need_symbol('c_longlong')
def test_longlongresult(self):
f = dll._testfunc_q_bhilfd
f.restype = c_longlong
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
result = f(1, 2, 3, 4, 5.0, 6.0)
self.assertEqual(result, 21)
f = dll._testfunc_q_bhilfdq
f.restype = c_longlong
f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong]
result = f(1, 2, 3, 4, 5.0, 6.0, 21)
self.assertEqual(result, 42)
def test_stringresult(self):
f = dll._testfunc_p_p
f.argtypes = None
f.restype = c_char_p
result = f(b"123")
self.assertEqual(result, b"123")
result = f(None)
self.assertEqual(result, None)
def test_pointers(self):
f = dll._testfunc_p_p
f.restype = POINTER(c_int)
f.argtypes = [POINTER(c_int)]
# This only works if the value c_int(42) passed to the
# function is still alive while the pointer (the result) is
# used.
v = c_int(42)
self.assertEqual(pointer(v).contents.value, 42)
result = f(pointer(v))
self.assertEqual(type(result), POINTER(c_int))
self.assertEqual(result.contents.value, 42)
# This on works...
result = f(pointer(v))
self.assertEqual(result.contents.value, v.value)
p = pointer(c_int(99))
result = f(p)
self.assertEqual(result.contents.value, 99)
arg = byref(v)
result = f(arg)
self.assertNotEqual(result.contents, v.value)
self.assertRaises(ArgumentError, f, byref(c_short(22)))
# It is dangerous, however, because you don't control the lifetime
# of the pointer:
result = f(byref(c_int(99)))
self.assertNotEqual(result.contents, 99)
################################################################
def test_shorts(self):
f = dll._testfunc_callback_i_if
args = []
expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
def callback(v):
args.append(v)
return v
CallBack = CFUNCTYPE(c_int, c_int)
cb = CallBack(callback)
f(2**18, cb)
self.assertEqual(args, expected)
################################################################
def test_callbacks(self):
f = dll._testfunc_callback_i_if
f.restype = c_int
f.argtypes = None
MyCallback = CFUNCTYPE(c_int, c_int)
def callback(value):
#print "called back with", value
return value
cb = MyCallback(callback)
result = f(-10, cb)
self.assertEqual(result, -18)
# test with prototype
f.argtypes = [c_int, MyCallback]
cb = MyCallback(callback)
result = f(-10, cb)
self.assertEqual(result, -18)
AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
# check that the prototype works: we call f with wrong
# argument types
cb = AnotherCallback(callback)
self.assertRaises(ArgumentError, f, -10, cb)
def test_callbacks_2(self):
# Can also use simple datatypes as argument type specifiers
# for the callback function.
# In this case the call receives an instance of that type
f = dll._testfunc_callback_i_if
f.restype = c_int
MyCallback = CFUNCTYPE(c_int, c_int)
f.argtypes = [c_int, MyCallback]
def callback(value):
#print "called back with", value
self.assertEqual(type(value), int)
return value
cb = MyCallback(callback)
result = f(-10, cb)
self.assertEqual(result, -18)
@need_symbol('c_longlong')
def test_longlong_callbacks(self):
f = dll._testfunc_callback_q_qf
f.restype = c_longlong
MyCallback = CFUNCTYPE(c_longlong, c_longlong)
f.argtypes = [c_longlong, MyCallback]
def callback(value):
self.assertIsInstance(value, int)
return value & 0x7FFFFFFF
cb = MyCallback(callback)
self.assertEqual(13577625587, f(1000000000000, cb))
def test_errors(self):
self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy")
self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy")
def test_byval(self):
# without prototype
ptin = POINT(1, 2)
ptout = POINT()
# EXPORT int _testfunc_byval(point in, point *pout)
result = dll._testfunc_byval(ptin, byref(ptout))
got = result, ptout.x, ptout.y
expected = 3, 1, 2
self.assertEqual(got, expected)
# with prototype
ptin = POINT(101, 102)
ptout = POINT()
dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
dll._testfunc_byval.restype = c_int
result = dll._testfunc_byval(ptin, byref(ptout))
got = result, ptout.x, ptout.y
expected = 203, 101, 102
self.assertEqual(got, expected)
def test_struct_return_2H(self):
class S2H(Structure):
_fields_ = [("x", c_short),
("y", c_short)]
dll.ret_2h_func.restype = S2H
dll.ret_2h_func.argtypes = [S2H]
inp = S2H(99, 88)
s2h = dll.ret_2h_func(inp)
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
def test_struct_return_2H_stdcall(self):
class S2H(Structure):
_fields_ = [("x", c_short),
("y", c_short)]
windll.s_ret_2h_func.restype = S2H
windll.s_ret_2h_func.argtypes = [S2H]
s2h = windll.s_ret_2h_func(S2H(99, 88))
self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
def test_struct_return_8H(self):
class S8I(Structure):
_fields_ = [("a", c_int),
("b", c_int),
("c", c_int),
("d", c_int),
("e", c_int),
("f", c_int),
("g", c_int),
("h", c_int)]
dll.ret_8i_func.restype = S8I
dll.ret_8i_func.argtypes = [S8I]
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
s8i = dll.ret_8i_func(inp)
self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
def test_struct_return_8H_stdcall(self):
class S8I(Structure):
_fields_ = [("a", c_int),
("b", c_int),
("c", c_int),
("d", c_int),
("e", c_int),
("f", c_int),
("g", c_int),
("h", c_int)]
windll.s_ret_8i_func.restype = S8I
windll.s_ret_8i_func.argtypes = [S8I]
inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
s8i = windll.s_ret_8i_func(inp)
self.assertEqual(
(s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
def test_sf1651235(self):
# see https://www.python.org/sf/1651235
proto = CFUNCTYPE(c_int, RECT, POINT)
def callback(*args):
return 0
callback = proto(callback)
self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
if __name__ == '__main__':
unittest.main()

42
Lib/ctypes/test/test_incomplete.py vendored Normal file
View File

@@ -0,0 +1,42 @@
import unittest
from ctypes import *
################################################################
#
# The incomplete pointer example from the tutorial
#
class MyTestCase(unittest.TestCase):
def test_incomplete_example(self):
lpcell = POINTER("cell")
class cell(Structure):
_fields_ = [("name", c_char_p),
("next", lpcell)]
SetPointerType(lpcell, cell)
c1 = cell()
c1.name = b"foo"
c2 = cell()
c2.name = b"bar"
c1.next = pointer(c2)
c2.next = pointer(c1)
p = c1
result = []
for i in range(8):
result.append(p.name)
p = p.next[0]
self.assertEqual(result, [b"foo", b"bar"] * 4)
# to not leak references, we must clean _pointer_type_cache
from ctypes import _pointer_type_cache
del _pointer_type_cache[cell]
################################################################
if __name__ == '__main__':
unittest.main()

40
Lib/ctypes/test/test_init.py vendored Normal file
View File

@@ -0,0 +1,40 @@
from ctypes import *
import unittest
class X(Structure):
_fields_ = [("a", c_int),
("b", c_int)]
new_was_called = False
def __new__(cls):
result = super().__new__(cls)
result.new_was_called = True
return result
def __init__(self):
self.a = 9
self.b = 12
class Y(Structure):
_fields_ = [("x", X)]
class InitTest(unittest.TestCase):
def test_get(self):
# make sure the only accessing a nested structure
# doesn't call the structure's __new__ and __init__
y = Y()
self.assertEqual((y.x.a, y.x.b), (0, 0))
self.assertEqual(y.x.new_was_called, False)
# But explicitly creating an X structure calls __new__ and __init__, of course.
x = X()
self.assertEqual((x.a, x.b), (9, 12))
self.assertEqual(x.new_was_called, True)
y.x = x
self.assertEqual((y.x.a, y.x.b), (9, 12))
self.assertEqual(y.x.new_was_called, False)
if __name__ == "__main__":
unittest.main()

100
Lib/ctypes/test/test_internals.py vendored Normal file
View File

@@ -0,0 +1,100 @@
# This tests the internal _objects attribute
import unittest
from ctypes import *
from sys import getrefcount as grc
# XXX This test must be reviewed for correctness!!!
# ctypes' types are container types.
#
# They have an internal memory block, which only consists of some bytes,
# but it has to keep references to other objects as well. This is not
# really needed for trivial C types like int or char, but it is important
# for aggregate types like strings or pointers in particular.
#
# What about pointers?
class ObjectsTestCase(unittest.TestCase):
def assertSame(self, a, b):
self.assertEqual(id(a), id(b))
def test_ints(self):
i = 42000123
refcnt = grc(i)
ci = c_int(i)
self.assertEqual(refcnt, grc(i))
self.assertEqual(ci._objects, None)
def test_c_char_p(self):
s = b"Hello, World"
refcnt = grc(s)
cs = c_char_p(s)
self.assertEqual(refcnt + 1, grc(s))
self.assertSame(cs._objects, s)
def test_simple_struct(self):
class X(Structure):
_fields_ = [("a", c_int), ("b", c_int)]
a = 421234
b = 421235
x = X()
self.assertEqual(x._objects, None)
x.a = a
x.b = b
self.assertEqual(x._objects, None)
def test_embedded_structs(self):
class X(Structure):
_fields_ = [("a", c_int), ("b", c_int)]
class Y(Structure):
_fields_ = [("x", X), ("y", X)]
y = Y()
self.assertEqual(y._objects, None)
x1, x2 = X(), X()
y.x, y.y = x1, x2
self.assertEqual(y._objects, {"0": {}, "1": {}})
x1.a, x2.b = 42, 93
self.assertEqual(y._objects, {"0": {}, "1": {}})
def test_xxx(self):
class X(Structure):
_fields_ = [("a", c_char_p), ("b", c_char_p)]
class Y(Structure):
_fields_ = [("x", X), ("y", X)]
s1 = b"Hello, World"
s2 = b"Hallo, Welt"
x = X()
x.a = s1
x.b = s2
self.assertEqual(x._objects, {"0": s1, "1": s2})
y = Y()
y.x = x
self.assertEqual(y._objects, {"0": {"0": s1, "1": s2}})
## x = y.x
## del y
## print x._b_base_._objects
def test_ptr_struct(self):
class X(Structure):
_fields_ = [("data", POINTER(c_int))]
A = c_int*4
a = A(11, 22, 33, 44)
self.assertEqual(a._objects, None)
x = X()
x.data = a
##XXX print x._objects
##XXX print x.data[0]
##XXX print x.data._objects
if __name__ == '__main__':
unittest.main()

153
Lib/ctypes/test/test_keeprefs.py vendored Normal file
View File

@@ -0,0 +1,153 @@
from ctypes import *
import unittest
class SimpleTestCase(unittest.TestCase):
def test_cint(self):
x = c_int()
self.assertEqual(x._objects, None)
x.value = 42
self.assertEqual(x._objects, None)
x = c_int(99)
self.assertEqual(x._objects, None)
def test_ccharp(self):
x = c_char_p()
self.assertEqual(x._objects, None)
x.value = b"abc"
self.assertEqual(x._objects, b"abc")
x = c_char_p(b"spam")
self.assertEqual(x._objects, b"spam")
class StructureTestCase(unittest.TestCase):
def test_cint_struct(self):
class X(Structure):
_fields_ = [("a", c_int),
("b", c_int)]
x = X()
self.assertEqual(x._objects, None)
x.a = 42
x.b = 99
self.assertEqual(x._objects, None)
def test_ccharp_struct(self):
class X(Structure):
_fields_ = [("a", c_char_p),
("b", c_char_p)]
x = X()
self.assertEqual(x._objects, None)
x.a = b"spam"
x.b = b"foo"
self.assertEqual(x._objects, {"0": b"spam", "1": b"foo"})
def test_struct_struct(self):
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
class RECT(Structure):
_fields_ = [("ul", POINT), ("lr", POINT)]
r = RECT()
r.ul.x = 0
r.ul.y = 1
r.lr.x = 2
r.lr.y = 3
self.assertEqual(r._objects, None)
r = RECT()
pt = POINT(1, 2)
r.ul = pt
self.assertEqual(r._objects, {'0': {}})
r.ul.x = 22
r.ul.y = 44
self.assertEqual(r._objects, {'0': {}})
r.lr = POINT()
self.assertEqual(r._objects, {'0': {}, '1': {}})
class ArrayTestCase(unittest.TestCase):
def test_cint_array(self):
INTARR = c_int * 3
ia = INTARR()
self.assertEqual(ia._objects, None)
ia[0] = 1
ia[1] = 2
ia[2] = 3
self.assertEqual(ia._objects, None)
class X(Structure):
_fields_ = [("x", c_int),
("a", INTARR)]
x = X()
x.x = 1000
x.a[0] = 42
x.a[1] = 96
self.assertEqual(x._objects, None)
x.a = ia
self.assertEqual(x._objects, {'1': {}})
class PointerTestCase(unittest.TestCase):
def test_p_cint(self):
i = c_int(42)
x = pointer(i)
self.assertEqual(x._objects, {'1': i})
class DeletePointerTestCase(unittest.TestCase):
@unittest.skip('test disabled')
def test_X(self):
class X(Structure):
_fields_ = [("p", POINTER(c_char_p))]
x = X()
i = c_char_p("abc def")
from sys import getrefcount as grc
print("2?", grc(i))
x.p = pointer(i)
print("3?", grc(i))
for i in range(320):
c_int(99)
x.p[0]
print(x.p[0])
## del x
## print "2?", grc(i)
## del i
import gc
gc.collect()
for i in range(320):
c_int(99)
x.p[0]
print(x.p[0])
print(x.p.contents)
## print x._objects
x.p[0] = "spam spam"
## print x.p[0]
print("+" * 42)
print(x._objects)
class PointerToStructure(unittest.TestCase):
def test(self):
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
class RECT(Structure):
_fields_ = [("a", POINTER(POINT)),
("b", POINTER(POINT))]
r = RECT()
p1 = POINT(1, 2)
r.a = pointer(p1)
r.b = pointer(p1)
## from pprint import pprint as pp
## pp(p1._objects)
## pp(r._objects)
r.a[0].x = 42
r.a[0].y = 99
# to avoid leaking when tests are run several times
# clean up the types left in the cache.
from ctypes import _pointer_type_cache
del _pointer_type_cache[POINT]
if __name__ == "__main__":
unittest.main()

33
Lib/ctypes/test/test_libc.py vendored Normal file
View File

@@ -0,0 +1,33 @@
import unittest
from ctypes import *
import _ctypes_test
lib = CDLL(_ctypes_test.__file__)
def three_way_cmp(x, y):
"""Return -1 if x < y, 0 if x == y and 1 if x > y"""
return (x > y) - (x < y)
class LibTest(unittest.TestCase):
def test_sqrt(self):
lib.my_sqrt.argtypes = c_double,
lib.my_sqrt.restype = c_double
self.assertEqual(lib.my_sqrt(4.0), 2.0)
import math
self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0))
def test_qsort(self):
comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char))
lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc
lib.my_qsort.restype = None
def sort(a, b):
return three_way_cmp(a[0], b[0])
chars = create_string_buffer(b"spam, spam, and spam")
lib.my_qsort(chars, len(chars)-1, sizeof(c_char), comparefunc(sort))
self.assertEqual(chars.raw, b" ,,aaaadmmmnpppsss\x00")
if __name__ == "__main__":
unittest.main()

182
Lib/ctypes/test/test_loading.py vendored Normal file
View File

@@ -0,0 +1,182 @@
from ctypes import *
import os
import shutil
import subprocess
import sys
import unittest
import test.support
from test.support import import_helper
from test.support import os_helper
from ctypes.util import find_library
libc_name = None
def setUpModule():
global libc_name
if os.name == "nt":
libc_name = find_library("c")
elif sys.platform == "cygwin":
libc_name = "cygwin1.dll"
else:
libc_name = find_library("c")
if test.support.verbose:
print("libc_name is", libc_name)
class LoaderTest(unittest.TestCase):
unknowndll = "xxrandomnamexx"
def test_load(self):
if libc_name is None:
self.skipTest('could not find libc')
CDLL(libc_name)
CDLL(os.path.basename(libc_name))
self.assertRaises(OSError, CDLL, self.unknowndll)
def test_load_version(self):
if libc_name is None:
self.skipTest('could not find libc')
if os.path.basename(libc_name) != 'libc.so.6':
self.skipTest('wrong libc path for test')
cdll.LoadLibrary("libc.so.6")
# linux uses version, libc 9 should not exist
self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9")
self.assertRaises(OSError, cdll.LoadLibrary, self.unknowndll)
def test_find(self):
for name in ("c", "m"):
lib = find_library(name)
if lib:
cdll.LoadLibrary(lib)
CDLL(lib)
@unittest.skipUnless(os.name == "nt",
'test specific to Windows')
def test_load_library(self):
# CRT is no longer directly loadable. See issue23606 for the
# discussion about alternative approaches.
#self.assertIsNotNone(libc_name)
if test.support.verbose:
print(find_library("kernel32"))
print(find_library("user32"))
if os.name == "nt":
windll.kernel32.GetModuleHandleW
windll["kernel32"].GetModuleHandleW
windll.LoadLibrary("kernel32").GetModuleHandleW
WinDLL("kernel32").GetModuleHandleW
# embedded null character
self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0")
@unittest.skipUnless(os.name == "nt",
'test specific to Windows')
def test_load_ordinal_functions(self):
import _ctypes_test
dll = WinDLL(_ctypes_test.__file__)
# We load the same function both via ordinal and name
func_ord = dll[2]
func_name = dll.GetString
# addressof gets the address where the function pointer is stored
a_ord = addressof(func_ord)
a_name = addressof(func_name)
f_ord_addr = c_void_p.from_address(a_ord).value
f_name_addr = c_void_p.from_address(a_name).value
self.assertEqual(hex(f_ord_addr), hex(f_name_addr))
self.assertRaises(AttributeError, dll.__getitem__, 1234)
@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
def test_1703286_A(self):
from _ctypes import LoadLibrary, FreeLibrary
# On winXP 64-bit, advapi32 loads at an address that does
# NOT fit into a 32-bit integer. FreeLibrary must be able
# to accept this address.
# These are tests for https://www.python.org/sf/1703286
handle = LoadLibrary("advapi32")
FreeLibrary(handle)
@unittest.skipUnless(os.name == "nt", 'Windows-specific test')
def test_1703286_B(self):
# Since on winXP 64-bit advapi32 loads like described
# above, the (arbitrarily selected) CloseEventLog function
# also has a high address. 'call_function' should accept
# addresses so large.
from _ctypes import call_function
advapi32 = windll.advapi32
# Calling CloseEventLog with a NULL argument should fail,
# but the call should not segfault or so.
self.assertEqual(0, advapi32.CloseEventLog(None))
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
windll.kernel32.GetProcAddress.restype = c_void_p
proc = windll.kernel32.GetProcAddress(advapi32._handle,
b"CloseEventLog")
self.assertTrue(proc)
# This is the real test: call the function via 'call_function'
self.assertEqual(0, call_function(proc, (None,)))
@unittest.skipUnless(os.name == "nt",
'test specific to Windows')
def test_load_dll_with_flags(self):
_sqlite3 = import_helper.import_module("_sqlite3")
src = _sqlite3.__file__
if src.lower().endswith("_d.pyd"):
ext = "_d.dll"
else:
ext = ".dll"
with os_helper.temp_dir() as tmp:
# We copy two files and load _sqlite3.dll (formerly .pyd),
# which has a dependency on sqlite3.dll. Then we test
# loading it in subprocesses to avoid it starting in memory
# for each test.
target = os.path.join(tmp, "_sqlite3.dll")
shutil.copy(src, target)
shutil.copy(os.path.join(os.path.dirname(src), "sqlite3" + ext),
os.path.join(tmp, "sqlite3" + ext))
def should_pass(command):
with self.subTest(command):
subprocess.check_output(
[sys.executable, "-c",
"from ctypes import *; import nt;" + command],
cwd=tmp
)
def should_fail(command):
with self.subTest(command):
with self.assertRaises(subprocess.CalledProcessError):
subprocess.check_output(
[sys.executable, "-c",
"from ctypes import *; import nt;" + command],
cwd=tmp, stderr=subprocess.STDOUT,
)
# Default load should not find this in CWD
should_fail("WinDLL('_sqlite3.dll')")
# Relative path (but not just filename) should succeed
should_pass("WinDLL('./_sqlite3.dll')")
# Insecure load flags should succeed
# Clear the DLL directory to avoid safe search settings propagating
should_pass("windll.kernel32.SetDllDirectoryW(None); WinDLL('_sqlite3.dll', winmode=0)")
# Full path load without DLL_LOAD_DIR shouldn't find dependency
should_fail("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
"winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32)")
# Full path load with DLL_LOAD_DIR should succeed
should_pass("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
"winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32|" +
"nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)")
# User-specified directory should succeed
should_pass("import os; p = os.add_dll_directory(os.getcwd());" +
"WinDLL('_sqlite3.dll'); p.close()")
if __name__ == "__main__":
unittest.main()

110
Lib/ctypes/test/test_macholib.py vendored Normal file
View File

@@ -0,0 +1,110 @@
import os
import sys
import unittest
# Bob Ippolito:
#
# Ok.. the code to find the filename for __getattr__ should look
# something like:
#
# import os
# from macholib.dyld import dyld_find
#
# def find_lib(name):
# possible = ['lib'+name+'.dylib', name+'.dylib',
# name+'.framework/'+name]
# for dylib in possible:
# try:
# return os.path.realpath(dyld_find(dylib))
# except ValueError:
# pass
# raise ValueError, "%s not found" % (name,)
#
# It'll have output like this:
#
# >>> find_lib('pthread')
# '/usr/lib/libSystem.B.dylib'
# >>> find_lib('z')
# '/usr/lib/libz.1.dylib'
# >>> find_lib('IOKit')
# '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit'
#
# -bob
from ctypes.macholib.dyld import dyld_find
from ctypes.macholib.dylib import dylib_info
from ctypes.macholib.framework import framework_info
def find_lib(name):
possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name]
for dylib in possible:
try:
return os.path.realpath(dyld_find(dylib))
except ValueError:
pass
raise ValueError("%s not found" % (name,))
def d(location=None, name=None, shortname=None, version=None, suffix=None):
return {'location': location, 'name': name, 'shortname': shortname,
'version': version, 'suffix': suffix}
class MachOTest(unittest.TestCase):
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
def test_find(self):
self.assertEqual(dyld_find('libSystem.dylib'),
'/usr/lib/libSystem.dylib')
self.assertEqual(dyld_find('System.framework/System'),
'/System/Library/Frameworks/System.framework/System')
# On Mac OS 11, system dylibs are only present in the shared cache,
# so symlinks like libpthread.dylib -> libSystem.B.dylib will not
# be resolved by dyld_find
self.assertIn(find_lib('pthread'),
('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib'))
result = find_lib('z')
# Issue #21093: dyld default search path includes $HOME/lib and
# /usr/local/lib before /usr/lib, which caused test failures if
# a local copy of libz exists in one of them. Now ignore the head
# of the path.
self.assertRegex(result, r".*/lib/libz.*\.dylib")
self.assertIn(find_lib('IOKit'),
('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit',
'/System/Library/Frameworks/IOKit.framework/IOKit'))
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
def test_info(self):
self.assertIsNone(dylib_info('completely/invalid'))
self.assertIsNone(dylib_info('completely/invalide_debug'))
self.assertEqual(dylib_info('P/Foo.dylib'), d('P', 'Foo.dylib', 'Foo'))
self.assertEqual(dylib_info('P/Foo_debug.dylib'),
d('P', 'Foo_debug.dylib', 'Foo', suffix='debug'))
self.assertEqual(dylib_info('P/Foo.A.dylib'),
d('P', 'Foo.A.dylib', 'Foo', 'A'))
self.assertEqual(dylib_info('P/Foo_debug.A.dylib'),
d('P', 'Foo_debug.A.dylib', 'Foo_debug', 'A'))
self.assertEqual(dylib_info('P/Foo.A_debug.dylib'),
d('P', 'Foo.A_debug.dylib', 'Foo', 'A', 'debug'))
@unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
def test_framework_info(self):
self.assertIsNone(framework_info('completely/invalid'))
self.assertIsNone(framework_info('completely/invalid/_debug'))
self.assertIsNone(framework_info('P/F.framework'))
self.assertIsNone(framework_info('P/F.framework/_debug'))
self.assertEqual(framework_info('P/F.framework/F'),
d('P', 'F.framework/F', 'F'))
self.assertEqual(framework_info('P/F.framework/F_debug'),
d('P', 'F.framework/F_debug', 'F', suffix='debug'))
self.assertIsNone(framework_info('P/F.framework/Versions'))
self.assertIsNone(framework_info('P/F.framework/Versions/A'))
self.assertEqual(framework_info('P/F.framework/Versions/A/F'),
d('P', 'F.framework/Versions/A/F', 'F', 'A'))
self.assertEqual(framework_info('P/F.framework/Versions/A/F_debug'),
d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug'))
if __name__ == "__main__":
unittest.main()

79
Lib/ctypes/test/test_memfunctions.py vendored Normal file
View File

@@ -0,0 +1,79 @@
import sys
from test import support
import unittest
from ctypes import *
from ctypes.test import need_symbol
class MemFunctionsTest(unittest.TestCase):
@unittest.skip('test disabled')
def test_overflow(self):
# string_at and wstring_at must use the Python calling
# convention (which acquires the GIL and checks the Python
# error flag). Provoke an error and catch it; see also issue
# #3554: <http://bugs.python.org/issue3554>
self.assertRaises((OverflowError, MemoryError, SystemError),
lambda: wstring_at(u"foo", sys.maxint - 1))
self.assertRaises((OverflowError, MemoryError, SystemError),
lambda: string_at("foo", sys.maxint - 1))
def test_memmove(self):
# large buffers apparently increase the chance that the memory
# is allocated in high address space.
a = create_string_buffer(1000000)
p = b"Hello, World"
result = memmove(a, p, len(p))
self.assertEqual(a.value, b"Hello, World")
self.assertEqual(string_at(result), b"Hello, World")
self.assertEqual(string_at(result, 5), b"Hello")
self.assertEqual(string_at(result, 16), b"Hello, World\0\0\0\0")
self.assertEqual(string_at(result, 0), b"")
def test_memset(self):
a = create_string_buffer(1000000)
result = memset(a, ord('x'), 16)
self.assertEqual(a.value, b"xxxxxxxxxxxxxxxx")
self.assertEqual(string_at(result), b"xxxxxxxxxxxxxxxx")
self.assertEqual(string_at(a), b"xxxxxxxxxxxxxxxx")
self.assertEqual(string_at(a, 20), b"xxxxxxxxxxxxxxxx\0\0\0\0")
def test_cast(self):
a = (c_ubyte * 32)(*map(ord, "abcdef"))
self.assertEqual(cast(a, c_char_p).value, b"abcdef")
self.assertEqual(cast(a, POINTER(c_byte))[:7],
[97, 98, 99, 100, 101, 102, 0])
self.assertEqual(cast(a, POINTER(c_byte))[:7:],
[97, 98, 99, 100, 101, 102, 0])
self.assertEqual(cast(a, POINTER(c_byte))[6:-1:-1],
[0, 102, 101, 100, 99, 98, 97])
self.assertEqual(cast(a, POINTER(c_byte))[:7:2],
[97, 99, 101, 0])
self.assertEqual(cast(a, POINTER(c_byte))[:7:7],
[97])
@support.refcount_test
def test_string_at(self):
s = string_at(b"foo bar")
# XXX The following may be wrong, depending on how Python
# manages string instances
self.assertEqual(2, sys.getrefcount(s))
self.assertTrue(s, "foo bar")
self.assertEqual(string_at(b"foo bar", 7), b"foo bar")
self.assertEqual(string_at(b"foo bar", 3), b"foo")
@need_symbol('create_unicode_buffer')
def test_wstring_at(self):
p = create_unicode_buffer("Hello, World")
a = create_unicode_buffer(1000000)
result = memmove(a, p, len(p) * sizeof(c_wchar))
self.assertEqual(a.value, "Hello, World")
self.assertEqual(wstring_at(a), "Hello, World")
self.assertEqual(wstring_at(a, 5), "Hello")
self.assertEqual(wstring_at(a, 16), "Hello, World\0\0\0\0")
self.assertEqual(wstring_at(a, 0), "")
if __name__ == "__main__":
unittest.main()

295
Lib/ctypes/test/test_numbers.py vendored Normal file
View File

@@ -0,0 +1,295 @@
from ctypes import *
import unittest
import struct
def valid_ranges(*types):
# given a sequence of numeric types, collect their _type_
# attribute, which is a single format character compatible with
# the struct module, use the struct module to calculate the
# minimum and maximum value allowed for this format.
# Returns a list of (min, max) values.
result = []
for t in types:
fmt = t._type_
size = struct.calcsize(fmt)
a = struct.unpack(fmt, (b"\x00"*32)[:size])[0]
b = struct.unpack(fmt, (b"\xFF"*32)[:size])[0]
c = struct.unpack(fmt, (b"\x7F"+b"\x00"*32)[:size])[0]
d = struct.unpack(fmt, (b"\x80"+b"\xFF"*32)[:size])[0]
result.append((min(a, b, c, d), max(a, b, c, d)))
return result
ArgType = type(byref(c_int(0)))
unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
signed_types = [c_byte, c_short, c_int, c_long, c_longlong]
bool_types = []
float_types = [c_double, c_float]
try:
c_ulonglong
c_longlong
except NameError:
pass
else:
unsigned_types.append(c_ulonglong)
signed_types.append(c_longlong)
try:
c_bool
except NameError:
pass
else:
bool_types.append(c_bool)
unsigned_ranges = valid_ranges(*unsigned_types)
signed_ranges = valid_ranges(*signed_types)
bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]
################################################################
class NumberTestCase(unittest.TestCase):
def test_default_init(self):
# default values are set to zero
for t in signed_types + unsigned_types + float_types:
self.assertEqual(t().value, 0)
def test_unsigned_values(self):
# the value given to the constructor is available
# as the 'value' attribute
for t, (l, h) in zip(unsigned_types, unsigned_ranges):
self.assertEqual(t(l).value, l)
self.assertEqual(t(h).value, h)
def test_signed_values(self):
# see above
for t, (l, h) in zip(signed_types, signed_ranges):
self.assertEqual(t(l).value, l)
self.assertEqual(t(h).value, h)
def test_bool_values(self):
from operator import truth
for t, v in zip(bool_types, bool_values):
self.assertEqual(t(v).value, truth(v))
def test_typeerror(self):
# Only numbers are allowed in the constructor,
# otherwise TypeError is raised
for t in signed_types + unsigned_types + float_types:
self.assertRaises(TypeError, t, "")
self.assertRaises(TypeError, t, None)
@unittest.skip('test disabled')
def test_valid_ranges(self):
# invalid values of the correct type
# raise ValueError (not OverflowError)
for t, (l, h) in zip(unsigned_types, unsigned_ranges):
self.assertRaises(ValueError, t, l-1)
self.assertRaises(ValueError, t, h+1)
def test_from_param(self):
# the from_param class method attribute always
# returns PyCArgObject instances
for t in signed_types + unsigned_types + float_types:
self.assertEqual(ArgType, type(t.from_param(0)))
def test_byref(self):
# calling byref returns also a PyCArgObject instance
for t in signed_types + unsigned_types + float_types + bool_types:
parm = byref(t())
self.assertEqual(ArgType, type(parm))
def test_floats(self):
# c_float and c_double can be created from
# Python int and float
class FloatLike(object):
def __float__(self):
return 2.0
f = FloatLike()
for t in float_types:
self.assertEqual(t(2.0).value, 2.0)
self.assertEqual(t(2).value, 2.0)
self.assertEqual(t(2).value, 2.0)
self.assertEqual(t(f).value, 2.0)
def test_integers(self):
class FloatLike(object):
def __float__(self):
return 2.0
f = FloatLike()
class IntLike(object):
def __int__(self):
return 2
d = IntLike()
class IndexLike(object):
def __index__(self):
return 2
i = IndexLike()
# integers cannot be constructed from floats,
# but from integer-like objects
for t in signed_types + unsigned_types:
self.assertRaises(TypeError, t, 3.14)
self.assertRaises(TypeError, t, f)
self.assertRaises(TypeError, t, d)
self.assertEqual(t(i).value, 2)
def test_sizes(self):
for t in signed_types + unsigned_types + float_types + bool_types:
try:
size = struct.calcsize(t._type_)
except struct.error:
continue
# sizeof of the type...
self.assertEqual(sizeof(t), size)
# and sizeof of an instance
self.assertEqual(sizeof(t()), size)
def test_alignments(self):
for t in signed_types + unsigned_types + float_types:
code = t._type_ # the typecode
align = struct.calcsize("c%c" % code) - struct.calcsize(code)
# alignment of the type...
self.assertEqual((code, alignment(t)),
(code, align))
# and alignment of an instance
self.assertEqual((code, alignment(t())),
(code, align))
def test_int_from_address(self):
from array import array
for t in signed_types + unsigned_types:
# the array module doesn't support all format codes
# (no 'q' or 'Q')
try:
array(t._type_)
except ValueError:
continue
a = array(t._type_, [100])
# v now is an integer at an 'external' memory location
v = t.from_address(a.buffer_info()[0])
self.assertEqual(v.value, a[0])
self.assertEqual(type(v), t)
# changing the value at the memory location changes v's value also
a[0] = 42
self.assertEqual(v.value, a[0])
def test_float_from_address(self):
from array import array
for t in float_types:
a = array(t._type_, [3.14])
v = t.from_address(a.buffer_info()[0])
self.assertEqual(v.value, a[0])
self.assertIs(type(v), t)
a[0] = 2.3456e17
self.assertEqual(v.value, a[0])
self.assertIs(type(v), t)
def test_char_from_address(self):
from ctypes import c_char
from array import array
a = array('b', [0])
a[0] = ord('x')
v = c_char.from_address(a.buffer_info()[0])
self.assertEqual(v.value, b'x')
self.assertIs(type(v), c_char)
a[0] = ord('?')
self.assertEqual(v.value, b'?')
# array does not support c_bool / 't'
@unittest.skip('test disabled')
def test_bool_from_address(self):
from ctypes import c_bool
from array import array
a = array(c_bool._type_, [True])
v = t.from_address(a.buffer_info()[0])
self.assertEqual(v.value, a[0])
self.assertEqual(type(v) is t)
a[0] = False
self.assertEqual(v.value, a[0])
self.assertEqual(type(v) is t)
def test_init(self):
# c_int() can be initialized from Python's int, and c_int.
# Not from c_long or so, which seems strange, abc should
# probably be changed:
self.assertRaises(TypeError, c_int, c_long(42))
def test_float_overflow(self):
import sys
big_int = int(sys.float_info.max) * 2
for t in float_types + [c_longdouble]:
self.assertRaises(OverflowError, t, big_int)
if (hasattr(t, "__ctype_be__")):
self.assertRaises(OverflowError, t.__ctype_be__, big_int)
if (hasattr(t, "__ctype_le__")):
self.assertRaises(OverflowError, t.__ctype_le__, big_int)
@unittest.skip('test disabled')
def test_perf(self):
check_perf()
from ctypes import _SimpleCData
class c_int_S(_SimpleCData):
_type_ = "i"
__slots__ = []
def run_test(rep, msg, func, arg=None):
## items = [None] * rep
items = range(rep)
from time import perf_counter as clock
if arg is not None:
start = clock()
for i in items:
func(arg); func(arg); func(arg); func(arg); func(arg)
stop = clock()
else:
start = clock()
for i in items:
func(); func(); func(); func(); func()
stop = clock()
print("%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep)))
def check_perf():
# Construct 5 objects
from ctypes import c_int
REP = 200000
run_test(REP, "int()", int)
run_test(REP, "int(999)", int)
run_test(REP, "c_int()", c_int)
run_test(REP, "c_int(999)", c_int)
run_test(REP, "c_int_S()", c_int_S)
run_test(REP, "c_int_S(999)", c_int_S)
# Python 2.3 -OO, win2k, P4 700 MHz:
#
# int(): 0.87 us
# int(999): 0.87 us
# c_int(): 3.35 us
# c_int(999): 3.34 us
# c_int_S(): 3.23 us
# c_int_S(999): 3.24 us
# Python 2.2 -OO, win2k, P4 700 MHz:
#
# int(): 0.89 us
# int(999): 0.89 us
# c_int(): 9.99 us
# c_int(999): 10.02 us
# c_int_S(): 9.87 us
# c_int_S(999): 9.85 us
if __name__ == '__main__':
## check_perf()
unittest.main()

67
Lib/ctypes/test/test_objects.py vendored Normal file
View File

@@ -0,0 +1,67 @@
r'''
This tests the '_objects' attribute of ctypes instances. '_objects'
holds references to objects that must be kept alive as long as the
ctypes instance, to make sure that the memory buffer is valid.
WARNING: The '_objects' attribute is exposed ONLY for debugging ctypes itself,
it MUST NEVER BE MODIFIED!
'_objects' is initialized to a dictionary on first use, before that it
is None.
Here is an array of string pointers:
>>> from ctypes import *
>>> array = (c_char_p * 5)()
>>> print(array._objects)
None
>>>
The memory block stores pointers to strings, and the strings itself
assigned from Python must be kept.
>>> array[4] = b'foo bar'
>>> array._objects
{'4': b'foo bar'}
>>> array[4]
b'foo bar'
>>>
It gets more complicated when the ctypes instance itself is contained
in a 'base' object.
>>> class X(Structure):
... _fields_ = [("x", c_int), ("y", c_int), ("array", c_char_p * 5)]
...
>>> x = X()
>>> print(x._objects)
None
>>>
The'array' attribute of the 'x' object shares part of the memory buffer
of 'x' ('_b_base_' is either None, or the root object owning the memory block):
>>> print(x.array._b_base_) # doctest: +ELLIPSIS
<ctypes.test.test_objects.X object at 0x...>
>>>
>>> x.array[0] = b'spam spam spam'
>>> x._objects
{'0:2': b'spam spam spam'}
>>> x.array._b_base_._objects
{'0:2': b'spam spam spam'}
>>>
'''
import unittest, doctest
import ctypes.test.test_objects
class TestCase(unittest.TestCase):
def test(self):
failures, tests = doctest.testmod(ctypes.test.test_objects)
self.assertFalse(failures, 'doctests failed, see output above')
if __name__ == '__main__':
doctest.testmod(ctypes.test.test_objects)

250
Lib/ctypes/test/test_parameters.py vendored Normal file
View File

@@ -0,0 +1,250 @@
import unittest
from ctypes.test import need_symbol
import test.support
class SimpleTypesTestCase(unittest.TestCase):
def setUp(self):
import ctypes
try:
from _ctypes import set_conversion_mode
except ImportError:
pass
else:
self.prev_conv_mode = set_conversion_mode("ascii", "strict")
def tearDown(self):
try:
from _ctypes import set_conversion_mode
except ImportError:
pass
else:
set_conversion_mode(*self.prev_conv_mode)
def test_subclasses(self):
from ctypes import c_void_p, c_char_p
# ctypes 0.9.5 and before did overwrite from_param in SimpleType_new
class CVOIDP(c_void_p):
def from_param(cls, value):
return value * 2
from_param = classmethod(from_param)
class CCHARP(c_char_p):
def from_param(cls, value):
return value * 4
from_param = classmethod(from_param)
self.assertEqual(CVOIDP.from_param("abc"), "abcabc")
self.assertEqual(CCHARP.from_param("abc"), "abcabcabcabc")
@need_symbol('c_wchar_p')
def test_subclasses_c_wchar_p(self):
from ctypes import c_wchar_p
class CWCHARP(c_wchar_p):
def from_param(cls, value):
return value * 3
from_param = classmethod(from_param)
self.assertEqual(CWCHARP.from_param("abc"), "abcabcabc")
# XXX Replace by c_char_p tests
def test_cstrings(self):
from ctypes import c_char_p
# c_char_p.from_param on a Python String packs the string
# into a cparam object
s = b"123"
self.assertIs(c_char_p.from_param(s)._obj, s)
# new in 0.9.1: convert (encode) unicode to ascii
self.assertEqual(c_char_p.from_param(b"123")._obj, b"123")
self.assertRaises(TypeError, c_char_p.from_param, "123\377")
self.assertRaises(TypeError, c_char_p.from_param, 42)
# calling c_char_p.from_param with a c_char_p instance
# returns the argument itself:
a = c_char_p(b"123")
self.assertIs(c_char_p.from_param(a), a)
@need_symbol('c_wchar_p')
def test_cw_strings(self):
from ctypes import c_wchar_p
c_wchar_p.from_param("123")
self.assertRaises(TypeError, c_wchar_p.from_param, 42)
self.assertRaises(TypeError, c_wchar_p.from_param, b"123\377")
pa = c_wchar_p.from_param(c_wchar_p("123"))
self.assertEqual(type(pa), c_wchar_p)
def test_int_pointers(self):
from ctypes import c_short, c_uint, c_int, c_long, POINTER, pointer
LPINT = POINTER(c_int)
## p = pointer(c_int(42))
## x = LPINT.from_param(p)
x = LPINT.from_param(pointer(c_int(42)))
self.assertEqual(x.contents.value, 42)
self.assertEqual(LPINT(c_int(42)).contents.value, 42)
self.assertEqual(LPINT.from_param(None), None)
if c_int != c_long:
self.assertRaises(TypeError, LPINT.from_param, pointer(c_long(42)))
self.assertRaises(TypeError, LPINT.from_param, pointer(c_uint(42)))
self.assertRaises(TypeError, LPINT.from_param, pointer(c_short(42)))
def test_byref_pointer(self):
# The from_param class method of POINTER(typ) classes accepts what is
# returned by byref(obj), it type(obj) == typ
from ctypes import c_short, c_uint, c_int, c_long, POINTER, byref
LPINT = POINTER(c_int)
LPINT.from_param(byref(c_int(42)))
self.assertRaises(TypeError, LPINT.from_param, byref(c_short(22)))
if c_int != c_long:
self.assertRaises(TypeError, LPINT.from_param, byref(c_long(22)))
self.assertRaises(TypeError, LPINT.from_param, byref(c_uint(22)))
def test_byref_pointerpointer(self):
# See above
from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
LPLPINT = POINTER(POINTER(c_int))
LPLPINT.from_param(byref(pointer(c_int(42))))
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_short(22))))
if c_int != c_long:
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_long(22))))
self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_uint(22))))
def test_array_pointers(self):
from ctypes import c_short, c_uint, c_int, c_long, POINTER
INTARRAY = c_int * 3
ia = INTARRAY()
self.assertEqual(len(ia), 3)
self.assertEqual([ia[i] for i in range(3)], [0, 0, 0])
# Pointers are only compatible with arrays containing items of
# the same type!
LPINT = POINTER(c_int)
LPINT.from_param((c_int*3)())
self.assertRaises(TypeError, LPINT.from_param, c_short*3)
self.assertRaises(TypeError, LPINT.from_param, c_long*3)
self.assertRaises(TypeError, LPINT.from_param, c_uint*3)
def test_noctypes_argtype(self):
import _ctypes_test
from ctypes import CDLL, c_void_p, ArgumentError
func = CDLL(_ctypes_test.__file__)._testfunc_p_p
func.restype = c_void_p
# TypeError: has no from_param method
self.assertRaises(TypeError, setattr, func, "argtypes", (object,))
class Adapter(object):
def from_param(cls, obj):
return None
func.argtypes = (Adapter(),)
self.assertEqual(func(None), None)
self.assertEqual(func(object()), None)
class Adapter(object):
def from_param(cls, obj):
return obj
func.argtypes = (Adapter(),)
# don't know how to convert parameter 1
self.assertRaises(ArgumentError, func, object())
self.assertEqual(func(c_void_p(42)), 42)
class Adapter(object):
def from_param(cls, obj):
raise ValueError(obj)
func.argtypes = (Adapter(),)
# ArgumentError: argument 1: ValueError: 99
self.assertRaises(ArgumentError, func, 99)
def test_abstract(self):
from ctypes import (Array, Structure, Union, _Pointer,
_SimpleCData, _CFuncPtr)
self.assertRaises(TypeError, Array.from_param, 42)
self.assertRaises(TypeError, Structure.from_param, 42)
self.assertRaises(TypeError, Union.from_param, 42)
self.assertRaises(TypeError, _CFuncPtr.from_param, 42)
self.assertRaises(TypeError, _Pointer.from_param, 42)
self.assertRaises(TypeError, _SimpleCData.from_param, 42)
@test.support.cpython_only
def test_issue31311(self):
# __setstate__ should neither raise a SystemError nor crash in case
# of a bad __dict__.
from ctypes import Structure
class BadStruct(Structure):
@property
def __dict__(self):
pass
with self.assertRaises(TypeError):
BadStruct().__setstate__({}, b'foo')
class WorseStruct(Structure):
@property
def __dict__(self):
1/0
with self.assertRaises(ZeroDivisionError):
WorseStruct().__setstate__({}, b'foo')
def test_parameter_repr(self):
from ctypes import (
c_bool,
c_char,
c_wchar,
c_byte,
c_ubyte,
c_short,
c_ushort,
c_int,
c_uint,
c_long,
c_ulong,
c_longlong,
c_ulonglong,
c_float,
c_double,
c_longdouble,
c_char_p,
c_wchar_p,
c_void_p,
)
self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
################################################################
if __name__ == '__main__':
unittest.main()

235
Lib/ctypes/test/test_pep3118.py vendored Normal file
View File

@@ -0,0 +1,235 @@
import unittest
from ctypes import *
import re, sys
if sys.byteorder == "little":
THIS_ENDIAN = "<"
OTHER_ENDIAN = ">"
else:
THIS_ENDIAN = ">"
OTHER_ENDIAN = "<"
def normalize(format):
# Remove current endian specifier and white space from a format
# string
if format is None:
return ""
format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
return re.sub(r"\s", "", format)
class Test(unittest.TestCase):
def test_native_types(self):
for tp, fmt, shape, itemtp in native_types:
ob = tp()
v = memoryview(ob)
try:
self.assertEqual(normalize(v.format), normalize(fmt))
if shape:
self.assertEqual(len(v), shape[0])
else:
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
# if requested. memoryview currently reconstructs missing
# stride information, so this assert will fail.
# self.assertEqual(v.strides, ())
# they are always read/write
self.assertFalse(v.readonly)
if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n * v.itemsize, len(v.tobytes()))
except:
# so that we can see the failing type
print(tp)
raise
def test_endian_types(self):
for tp, fmt, shape, itemtp in endian_types:
ob = tp()
v = memoryview(ob)
try:
self.assertEqual(v.format, fmt)
if shape:
self.assertEqual(len(v), shape[0])
else:
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851
# self.assertEqual(v.strides, ())
# they are always read/write
self.assertFalse(v.readonly)
if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n, len(v))
except:
# so that we can see the failing type
print(tp)
raise
# define some structure classes
class Point(Structure):
_fields_ = [("x", c_long), ("y", c_long)]
class PackedPoint(Structure):
_pack_ = 2
_fields_ = [("x", c_long), ("y", c_long)]
class Point2(Structure):
pass
Point2._fields_ = [("x", c_long), ("y", c_long)]
class EmptyStruct(Structure):
_fields_ = []
class aUnion(Union):
_fields_ = [("a", c_int)]
class StructWithArrays(Structure):
_fields_ = [("x", c_long * 3 * 2), ("y", Point * 4)]
class Incomplete(Structure):
pass
class Complete(Structure):
pass
PComplete = POINTER(Complete)
Complete._fields_ = [("a", c_long)]
################################################################
#
# This table contains format strings as they look on little endian
# machines. The test replaces '<' with '>' on big endian machines.
#
# Platform-specific type codes
s_bool = {1: '?', 2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_bool)]
s_short = {2: 'h', 4: 'l', 8: 'q'}[sizeof(c_short)]
s_ushort = {2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_ushort)]
s_int = {2: 'h', 4: 'i', 8: 'q'}[sizeof(c_int)]
s_uint = {2: 'H', 4: 'I', 8: 'Q'}[sizeof(c_uint)]
s_long = {4: 'l', 8: 'q'}[sizeof(c_long)]
s_ulong = {4: 'L', 8: 'Q'}[sizeof(c_ulong)]
s_longlong = "q"
s_ulonglong = "Q"
s_float = "f"
s_double = "d"
s_longdouble = "g"
# Alias definitions in ctypes/__init__.py
if c_int is c_long:
s_int = s_long
if c_uint is c_ulong:
s_uint = s_ulong
if c_longlong is c_long:
s_longlong = s_long
if c_ulonglong is c_ulong:
s_ulonglong = s_ulong
if c_longdouble is c_double:
s_longdouble = s_double
native_types = [
# type format shape calc itemsize
## simple types
(c_char, "<c", (), c_char),
(c_byte, "<b", (), c_byte),
(c_ubyte, "<B", (), c_ubyte),
(c_short, "<" + s_short, (), c_short),
(c_ushort, "<" + s_ushort, (), c_ushort),
(c_int, "<" + s_int, (), c_int),
(c_uint, "<" + s_uint, (), c_uint),
(c_long, "<" + s_long, (), c_long),
(c_ulong, "<" + s_ulong, (), c_ulong),
(c_longlong, "<" + s_longlong, (), c_longlong),
(c_ulonglong, "<" + s_ulonglong, (), c_ulonglong),
(c_float, "<f", (), c_float),
(c_double, "<d", (), c_double),
(c_longdouble, "<" + s_longdouble, (), c_longdouble),
(c_bool, "<" + s_bool, (), c_bool),
(py_object, "<O", (), py_object),
## pointers
(POINTER(c_byte), "&<b", (), POINTER(c_byte)),
(POINTER(POINTER(c_long)), "&&<" + s_long, (), POINTER(POINTER(c_long))),
## arrays and pointers
(c_double * 4, "<d", (4,), c_double),
(c_double * 0, "<d", (0,), c_double),
(c_float * 4 * 3 * 2, "<f", (2,3,4), c_float),
(c_float * 4 * 0 * 2, "<f", (2,0,4), c_float),
(POINTER(c_short) * 2, "&<" + s_short, (2,), POINTER(c_short)),
(POINTER(c_short) * 2 * 3, "&<" + s_short, (3,2,), POINTER(c_short)),
(POINTER(c_short * 2), "&(2)<" + s_short, (), POINTER(c_short)),
## structures and unions
(Point, "T{<l:x:<l:y:}".replace('l', s_long), (), Point),
# packed structures do not implement the pep
(PackedPoint, "B", (), PackedPoint),
(Point2, "T{<l:x:<l:y:}".replace('l', s_long), (), Point2),
(EmptyStruct, "T{}", (), EmptyStruct),
# the pep doesn't support unions
(aUnion, "B", (), aUnion),
# structure with sub-arrays
(StructWithArrays, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (), StructWithArrays),
(StructWithArrays * 3, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (3,), StructWithArrays),
## pointer to incomplete structure
(Incomplete, "B", (), Incomplete),
(POINTER(Incomplete), "&B", (), POINTER(Incomplete)),
# 'Complete' is a structure that starts incomplete, but is completed after the
# pointer type to it has been created.
(Complete, "T{<l:a:}".replace('l', s_long), (), Complete),
# Unfortunately the pointer format string is not fixed...
(POINTER(Complete), "&B", (), POINTER(Complete)),
## other
# function signatures are not implemented
(CFUNCTYPE(None), "X{}", (), CFUNCTYPE(None)),
]
class BEPoint(BigEndianStructure):
_fields_ = [("x", c_long), ("y", c_long)]
class LEPoint(LittleEndianStructure):
_fields_ = [("x", c_long), ("y", c_long)]
################################################################
#
# This table contains format strings as they really look, on both big
# and little endian machines.
#
endian_types = [
(BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
(LEPoint, "T{<l:x:<l:y:}".replace('l', s_long), (), LEPoint),
(POINTER(BEPoint), "&T{>l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)),
(POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)),
]
if __name__ == "__main__":
unittest.main()

81
Lib/ctypes/test/test_pickling.py vendored Normal file
View File

@@ -0,0 +1,81 @@
import unittest
import pickle
from ctypes import *
import _ctypes_test
dll = CDLL(_ctypes_test.__file__)
class X(Structure):
_fields_ = [("a", c_int), ("b", c_double)]
init_called = 0
def __init__(self, *args, **kw):
X.init_called += 1
self.x = 42
class Y(X):
_fields_ = [("str", c_char_p)]
class PickleTest:
def dumps(self, item):
return pickle.dumps(item, self.proto)
def loads(self, item):
return pickle.loads(item)
def test_simple(self):
for src in [
c_int(42),
c_double(3.14),
]:
dst = self.loads(self.dumps(src))
self.assertEqual(src.__dict__, dst.__dict__)
self.assertEqual(memoryview(src).tobytes(),
memoryview(dst).tobytes())
def test_struct(self):
X.init_called = 0
x = X()
x.a = 42
self.assertEqual(X.init_called, 1)
y = self.loads(self.dumps(x))
# loads must NOT call __init__
self.assertEqual(X.init_called, 1)
# ctypes instances are identical when the instance __dict__
# and the memory buffer are identical
self.assertEqual(y.__dict__, x.__dict__)
self.assertEqual(memoryview(y).tobytes(),
memoryview(x).tobytes())
def test_unpickable(self):
# ctypes objects that are pointers or contain pointers are
# unpickable.
self.assertRaises(ValueError, lambda: self.dumps(Y()))
prototype = CFUNCTYPE(c_int)
for item in [
c_char_p(),
c_wchar_p(),
c_void_p(),
pointer(c_int(42)),
dll._testfunc_p_p,
prototype(lambda: 42),
]:
self.assertRaises(ValueError, lambda: self.dumps(item))
def test_wchar(self):
self.dumps(c_char(b"x"))
# Issue 5049
self.dumps(c_wchar("x"))
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
name = 'PickleTest_%s' % proto
globals()[name] = type(name,
(PickleTest, unittest.TestCase),
{'proto': proto})
if __name__ == "__main__":
unittest.main()

223
Lib/ctypes/test/test_pointers.py vendored Normal file
View File

@@ -0,0 +1,223 @@
import unittest, sys
from ctypes import *
import _ctypes_test
ctype_types = [c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint,
c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float]
python_types = [int, int, int, int, int, int,
int, int, int, int, float, float]
class PointersTestCase(unittest.TestCase):
def test_pointer_crash(self):
class A(POINTER(c_ulong)):
pass
POINTER(c_ulong)(c_ulong(22))
# Pointer can't set contents: has no _type_
self.assertRaises(TypeError, A, c_ulong(33))
def test_pass_pointers(self):
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_p_p
if sizeof(c_longlong) == sizeof(c_void_p):
func.restype = c_longlong
else:
func.restype = c_long
i = c_int(12345678)
## func.argtypes = (POINTER(c_int),)
address = func(byref(i))
self.assertEqual(c_int.from_address(address).value, 12345678)
func.restype = POINTER(c_int)
res = func(pointer(i))
self.assertEqual(res.contents.value, 12345678)
self.assertEqual(res[0], 12345678)
def test_change_pointers(self):
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_p_p
i = c_int(87654)
func.restype = POINTER(c_int)
func.argtypes = (POINTER(c_int),)
res = func(pointer(i))
self.assertEqual(res[0], 87654)
self.assertEqual(res.contents.value, 87654)
# C code: *res = 54345
res[0] = 54345
self.assertEqual(i.value, 54345)
# C code:
# int x = 12321;
# res = &x
x = c_int(12321)
res.contents = x
self.assertEqual(i.value, 54345)
x.value = -99
self.assertEqual(res.contents.value, -99)
def test_callbacks_with_pointers(self):
# a function type receiving a pointer
PROTOTYPE = CFUNCTYPE(c_int, POINTER(c_int))
self.result = []
def func(arg):
for i in range(10):
## print arg[i],
self.result.append(arg[i])
## print
return 0
callback = PROTOTYPE(func)
dll = CDLL(_ctypes_test.__file__)
# This function expects a function pointer,
# and calls this with an integer pointer as parameter.
# The int pointer points to a table containing the numbers 1..10
doit = dll._testfunc_callback_with_pointer
## i = c_int(42)
## callback(byref(i))
## self.assertEqual(i.value, 84)
doit(callback)
## print self.result
doit(callback)
## print self.result
def test_basics(self):
from operator import delitem
for ct, pt in zip(ctype_types, python_types):
i = ct(42)
p = pointer(i)
## print type(p.contents), ct
self.assertIs(type(p.contents), ct)
# p.contents is the same as p[0]
## print p.contents
## self.assertEqual(p.contents, 42)
## self.assertEqual(p[0], 42)
self.assertRaises(TypeError, delitem, p, 0)
def test_from_address(self):
from array import array
a = array('i', [100, 200, 300, 400, 500])
addr = a.buffer_info()[0]
p = POINTER(POINTER(c_int))
## print dir(p)
## print p.from_address
## print p.from_address(addr)[0][0]
def test_other(self):
class Table(Structure):
_fields_ = [("a", c_int),
("b", c_int),
("c", c_int)]
pt = pointer(Table(1, 2, 3))
self.assertEqual(pt.contents.a, 1)
self.assertEqual(pt.contents.b, 2)
self.assertEqual(pt.contents.c, 3)
pt.contents.c = 33
from ctypes import _pointer_type_cache
del _pointer_type_cache[Table]
def test_basic(self):
p = pointer(c_int(42))
# Although a pointer can be indexed, it has no length
self.assertRaises(TypeError, len, p)
self.assertEqual(p[0], 42)
self.assertEqual(p[0:1], [42])
self.assertEqual(p.contents.value, 42)
def test_charpp(self):
"""Test that a character pointer-to-pointer is correctly passed"""
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_c_p_p
func.restype = c_char_p
argv = (c_char_p * 2)()
argc = c_int( 2 )
argv[0] = b'hello'
argv[1] = b'world'
result = func( byref(argc), argv )
self.assertEqual(result, b'world')
def test_bug_1467852(self):
# http://sourceforge.net/tracker/?func=detail&atid=532154&aid=1467852&group_id=71702
x = c_int(5)
dummy = []
for i in range(32000):
dummy.append(c_int(i))
y = c_int(6)
p = pointer(x)
pp = pointer(p)
q = pointer(y)
pp[0] = q # <==
self.assertEqual(p[0], 6)
def test_c_void_p(self):
# http://sourceforge.net/tracker/?func=detail&aid=1518190&group_id=5470&atid=105470
if sizeof(c_void_p) == 4:
self.assertEqual(c_void_p(0xFFFFFFFF).value,
c_void_p(-1).value)
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
c_void_p(-1).value)
elif sizeof(c_void_p) == 8:
self.assertEqual(c_void_p(0xFFFFFFFF).value,
0xFFFFFFFF)
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
c_void_p(-1).value)
self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFFFFFFFFFF).value,
c_void_p(-1).value)
self.assertRaises(TypeError, c_void_p, 3.14) # make sure floats are NOT accepted
self.assertRaises(TypeError, c_void_p, object()) # nor other objects
def test_pointers_bool(self):
# NULL pointers have a boolean False value, non-NULL pointers True.
self.assertEqual(bool(POINTER(c_int)()), False)
self.assertEqual(bool(pointer(c_int())), True)
self.assertEqual(bool(CFUNCTYPE(None)(0)), False)
self.assertEqual(bool(CFUNCTYPE(None)(42)), True)
# COM methods are boolean True:
if sys.platform == "win32":
mth = WINFUNCTYPE(None)(42, "name", (), None)
self.assertEqual(bool(mth), True)
def test_pointer_type_name(self):
LargeNamedType = type('T' * 2 ** 25, (Structure,), {})
self.assertTrue(POINTER(LargeNamedType))
# to not leak references, we must clean _pointer_type_cache
from ctypes import _pointer_type_cache
del _pointer_type_cache[LargeNamedType]
def test_pointer_type_str_name(self):
large_string = 'T' * 2 ** 25
P = POINTER(large_string)
self.assertTrue(P)
# to not leak references, we must clean _pointer_type_cache
from ctypes import _pointer_type_cache
del _pointer_type_cache[id(P)]
def test_abstract(self):
from ctypes import _Pointer
self.assertRaises(TypeError, _Pointer.set_type, 42)
if __name__ == '__main__':
unittest.main()

222
Lib/ctypes/test/test_prototypes.py vendored Normal file
View File

@@ -0,0 +1,222 @@
from ctypes import *
from ctypes.test import need_symbol
import unittest
# IMPORTANT INFO:
#
# Consider this call:
# func.restype = c_char_p
# func(c_char_p("123"))
# It returns
# "123"
#
# WHY IS THIS SO?
#
# argument tuple (c_char_p("123"), ) is destroyed after the function
# func is called, but NOT before the result is actually built.
#
# If the arglist would be destroyed BEFORE the result has been built,
# the c_char_p("123") object would already have a zero refcount,
# and the pointer passed to (and returned by) the function would
# probably point to deallocated space.
#
# In this case, there would have to be an additional reference to the argument...
import _ctypes_test
testdll = CDLL(_ctypes_test.__file__)
# Return machine address `a` as a (possibly long) non-negative integer.
# Starting with Python 2.5, id(anything) is always non-negative, and
# the ctypes addressof() inherits that via PyLong_FromVoidPtr().
def positive_address(a):
if a >= 0:
return a
# View the bits in `a` as unsigned instead.
import struct
num_bits = struct.calcsize("P") * 8 # num bits in native machine address
a += 1 << num_bits
assert a >= 0
return a
def c_wbuffer(init):
n = len(init) + 1
return (c_wchar * n)(*init)
class CharPointersTestCase(unittest.TestCase):
def setUp(self):
func = testdll._testfunc_p_p
func.restype = c_long
func.argtypes = None
def test_paramflags(self):
# function returns c_void_p result,
# and has a required parameter named 'input'
prototype = CFUNCTYPE(c_void_p, c_void_p)
func = prototype(("_testfunc_p_p", testdll),
((1, "input"),))
try:
func()
except TypeError as details:
self.assertEqual(str(details), "required argument 'input' missing")
else:
self.fail("TypeError not raised")
self.assertEqual(func(None), None)
self.assertEqual(func(input=None), None)
def test_int_pointer_arg(self):
func = testdll._testfunc_p_p
if sizeof(c_longlong) == sizeof(c_void_p):
func.restype = c_longlong
else:
func.restype = c_long
self.assertEqual(0, func(0))
ci = c_int(0)
func.argtypes = POINTER(c_int),
self.assertEqual(positive_address(addressof(ci)),
positive_address(func(byref(ci))))
func.argtypes = c_char_p,
self.assertRaises(ArgumentError, func, byref(ci))
func.argtypes = POINTER(c_short),
self.assertRaises(ArgumentError, func, byref(ci))
func.argtypes = POINTER(c_double),
self.assertRaises(ArgumentError, func, byref(ci))
def test_POINTER_c_char_arg(self):
func = testdll._testfunc_p_p
func.restype = c_char_p
func.argtypes = POINTER(c_char),
self.assertEqual(None, func(None))
self.assertEqual(b"123", func(b"123"))
self.assertEqual(None, func(c_char_p(None)))
self.assertEqual(b"123", func(c_char_p(b"123")))
self.assertEqual(b"123", func(c_buffer(b"123")))
ca = c_char(b"a")
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
self.assertEqual(ord(b"a"), func(byref(ca))[0])
def test_c_char_p_arg(self):
func = testdll._testfunc_p_p
func.restype = c_char_p
func.argtypes = c_char_p,
self.assertEqual(None, func(None))
self.assertEqual(b"123", func(b"123"))
self.assertEqual(None, func(c_char_p(None)))
self.assertEqual(b"123", func(c_char_p(b"123")))
self.assertEqual(b"123", func(c_buffer(b"123")))
ca = c_char(b"a")
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
self.assertEqual(ord(b"a"), func(byref(ca))[0])
def test_c_void_p_arg(self):
func = testdll._testfunc_p_p
func.restype = c_char_p
func.argtypes = c_void_p,
self.assertEqual(None, func(None))
self.assertEqual(b"123", func(b"123"))
self.assertEqual(b"123", func(c_char_p(b"123")))
self.assertEqual(None, func(c_char_p(None)))
self.assertEqual(b"123", func(c_buffer(b"123")))
ca = c_char(b"a")
self.assertEqual(ord(b"a"), func(pointer(ca))[0])
self.assertEqual(ord(b"a"), func(byref(ca))[0])
func(byref(c_int()))
func(pointer(c_int()))
func((c_int * 3)())
@need_symbol('c_wchar_p')
def test_c_void_p_arg_with_c_wchar_p(self):
func = testdll._testfunc_p_p
func.restype = c_wchar_p
func.argtypes = c_void_p,
self.assertEqual(None, func(c_wchar_p(None)))
self.assertEqual("123", func(c_wchar_p("123")))
def test_instance(self):
func = testdll._testfunc_p_p
func.restype = c_void_p
class X:
_as_parameter_ = None
func.argtypes = c_void_p,
self.assertEqual(None, func(X()))
func.argtypes = None
self.assertEqual(None, func(X()))
@need_symbol('c_wchar')
class WCharPointersTestCase(unittest.TestCase):
def setUp(self):
func = testdll._testfunc_p_p
func.restype = c_int
func.argtypes = None
def test_POINTER_c_wchar_arg(self):
func = testdll._testfunc_p_p
func.restype = c_wchar_p
func.argtypes = POINTER(c_wchar),
self.assertEqual(None, func(None))
self.assertEqual("123", func("123"))
self.assertEqual(None, func(c_wchar_p(None)))
self.assertEqual("123", func(c_wchar_p("123")))
self.assertEqual("123", func(c_wbuffer("123")))
ca = c_wchar("a")
self.assertEqual("a", func(pointer(ca))[0])
self.assertEqual("a", func(byref(ca))[0])
def test_c_wchar_p_arg(self):
func = testdll._testfunc_p_p
func.restype = c_wchar_p
func.argtypes = c_wchar_p,
c_wchar_p.from_param("123")
self.assertEqual(None, func(None))
self.assertEqual("123", func("123"))
self.assertEqual(None, func(c_wchar_p(None)))
self.assertEqual("123", func(c_wchar_p("123")))
# XXX Currently, these raise TypeErrors, although they shouldn't:
self.assertEqual("123", func(c_wbuffer("123")))
ca = c_wchar("a")
self.assertEqual("a", func(pointer(ca))[0])
self.assertEqual("a", func(byref(ca))[0])
class ArrayTest(unittest.TestCase):
def test(self):
func = testdll._testfunc_ai8
func.restype = POINTER(c_int)
func.argtypes = c_int * 8,
func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8))
# This did crash before:
def func(): pass
CFUNCTYPE(None, c_int * 3)(func)
################################################################
if __name__ == '__main__':
unittest.main()

85
Lib/ctypes/test/test_python_api.py vendored Normal file
View File

@@ -0,0 +1,85 @@
from ctypes import *
import unittest
from test import support
################################################################
# This section should be moved into ctypes\__init__.py, when it's ready.
from _ctypes import PyObj_FromPtr
################################################################
from sys import getrefcount as grc
class PythonAPITestCase(unittest.TestCase):
def test_PyBytes_FromStringAndSize(self):
PyBytes_FromStringAndSize = pythonapi.PyBytes_FromStringAndSize
PyBytes_FromStringAndSize.restype = py_object
PyBytes_FromStringAndSize.argtypes = c_char_p, c_size_t
self.assertEqual(PyBytes_FromStringAndSize(b"abcdefghi", 3), b"abc")
@support.refcount_test
def test_PyString_FromString(self):
pythonapi.PyBytes_FromString.restype = py_object
pythonapi.PyBytes_FromString.argtypes = (c_char_p,)
s = b"abc"
refcnt = grc(s)
pyob = pythonapi.PyBytes_FromString(s)
self.assertEqual(grc(s), refcnt)
self.assertEqual(s, pyob)
del pyob
self.assertEqual(grc(s), refcnt)
@support.refcount_test
def test_PyLong_Long(self):
ref42 = grc(42)
pythonapi.PyLong_FromLong.restype = py_object
self.assertEqual(pythonapi.PyLong_FromLong(42), 42)
self.assertEqual(grc(42), ref42)
pythonapi.PyLong_AsLong.argtypes = (py_object,)
pythonapi.PyLong_AsLong.restype = c_long
res = pythonapi.PyLong_AsLong(42)
self.assertEqual(grc(res), ref42 + 1)
del res
self.assertEqual(grc(42), ref42)
@support.refcount_test
def test_PyObj_FromPtr(self):
s = "abc def ghi jkl"
ref = grc(s)
# id(python-object) is the address
pyobj = PyObj_FromPtr(id(s))
self.assertIs(s, pyobj)
self.assertEqual(grc(s), ref + 1)
del pyobj
self.assertEqual(grc(s), ref)
def test_PyOS_snprintf(self):
PyOS_snprintf = pythonapi.PyOS_snprintf
PyOS_snprintf.argtypes = POINTER(c_char), c_size_t, c_char_p
buf = c_buffer(256)
PyOS_snprintf(buf, sizeof(buf), b"Hello from %s", b"ctypes")
self.assertEqual(buf.value, b"Hello from ctypes")
PyOS_snprintf(buf, sizeof(buf), b"Hello from %s (%d, %d, %d)", b"ctypes", 1, 2, 3)
self.assertEqual(buf.value, b"Hello from ctypes (1, 2, 3)")
# not enough arguments
self.assertRaises(TypeError, PyOS_snprintf, buf)
def test_pyobject_repr(self):
self.assertEqual(repr(py_object()), "py_object(<NULL>)")
self.assertEqual(repr(py_object(42)), "py_object(42)")
self.assertEqual(repr(py_object(object)), "py_object(%r)" % object)
if __name__ == "__main__":
unittest.main()

77
Lib/ctypes/test/test_random_things.py vendored Normal file
View File

@@ -0,0 +1,77 @@
from ctypes import *
import contextlib
from test import support
import unittest
import sys
def callback_func(arg):
42 / arg
raise ValueError(arg)
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class call_function_TestCase(unittest.TestCase):
# _ctypes.call_function is deprecated and private, but used by
# Gary Bishp's readline module. If we have it, we must test it as well.
def test(self):
from _ctypes import call_function
windll.kernel32.LoadLibraryA.restype = c_void_p
windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
windll.kernel32.GetProcAddress.restype = c_void_p
hdll = windll.kernel32.LoadLibraryA(b"kernel32")
funcaddr = windll.kernel32.GetProcAddress(hdll, b"GetModuleHandleA")
self.assertEqual(call_function(funcaddr, (None,)),
windll.kernel32.GetModuleHandleA(None))
class CallbackTracbackTestCase(unittest.TestCase):
# When an exception is raised in a ctypes callback function, the C
# code prints a traceback.
#
# This test makes sure the exception types *and* the exception
# value is printed correctly.
#
# Changed in 0.9.3: No longer is '(in callback)' prepended to the
# error message - instead an additional frame for the C code is
# created, then a full traceback printed. When SystemExit is
# raised in a callback function, the interpreter exits.
@contextlib.contextmanager
def expect_unraisable(self, exc_type, exc_msg=None):
with support.catch_unraisable_exception() as cm:
yield
self.assertIsInstance(cm.unraisable.exc_value, exc_type)
if exc_msg is not None:
self.assertEqual(str(cm.unraisable.exc_value), exc_msg)
self.assertEqual(cm.unraisable.err_msg,
"Exception ignored on calling ctypes "
"callback function")
self.assertIs(cm.unraisable.object, callback_func)
def test_ValueError(self):
cb = CFUNCTYPE(c_int, c_int)(callback_func)
with self.expect_unraisable(ValueError, '42'):
cb(42)
def test_IntegerDivisionError(self):
cb = CFUNCTYPE(c_int, c_int)(callback_func)
with self.expect_unraisable(ZeroDivisionError):
cb(0)
def test_FloatDivisionError(self):
cb = CFUNCTYPE(c_int, c_double)(callback_func)
with self.expect_unraisable(ZeroDivisionError):
cb(0.0)
def test_TypeErrorDivisionError(self):
cb = CFUNCTYPE(c_int, c_char_p)(callback_func)
err_msg = "unsupported operand type(s) for /: 'int' and 'bytes'"
with self.expect_unraisable(TypeError, err_msg):
cb(b"spam")
if __name__ == '__main__':
unittest.main()

116
Lib/ctypes/test/test_refcounts.py vendored Normal file
View File

@@ -0,0 +1,116 @@
import unittest
from test import support
import ctypes
import gc
MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong)
import _ctypes_test
dll = ctypes.CDLL(_ctypes_test.__file__)
class RefcountTestCase(unittest.TestCase):
@support.refcount_test
def test_1(self):
from sys import getrefcount as grc
f = dll._testfunc_callback_i_if
f.restype = ctypes.c_int
f.argtypes = [ctypes.c_int, MyCallback]
def callback(value):
#print "called back with", value
return value
self.assertEqual(grc(callback), 2)
cb = MyCallback(callback)
self.assertGreater(grc(callback), 2)
result = f(-10, cb)
self.assertEqual(result, -18)
cb = None
gc.collect()
self.assertEqual(grc(callback), 2)
@support.refcount_test
def test_refcount(self):
from sys import getrefcount as grc
def func(*args):
pass
# this is the standard refcount for func
self.assertEqual(grc(func), 2)
# the CFuncPtr instance holds at least one refcount on func:
f = OtherCallback(func)
self.assertGreater(grc(func), 2)
# and may release it again
del f
self.assertGreaterEqual(grc(func), 2)
# but now it must be gone
gc.collect()
self.assertEqual(grc(func), 2)
class X(ctypes.Structure):
_fields_ = [("a", OtherCallback)]
x = X()
x.a = OtherCallback(func)
# the CFuncPtr instance holds at least one refcount on func:
self.assertGreater(grc(func), 2)
# and may release it again
del x
self.assertGreaterEqual(grc(func), 2)
# and now it must be gone again
gc.collect()
self.assertEqual(grc(func), 2)
f = OtherCallback(func)
# the CFuncPtr instance holds at least one refcount on func:
self.assertGreater(grc(func), 2)
# create a cycle
f.cycle = f
del f
gc.collect()
self.assertEqual(grc(func), 2)
class AnotherLeak(unittest.TestCase):
def test_callback(self):
import sys
proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
def func(a, b):
return a * b * 2
f = proto(func)
a = sys.getrefcount(ctypes.c_int)
f(1, 2)
self.assertEqual(sys.getrefcount(ctypes.c_int), a)
@support.refcount_test
def test_callback_py_object_none_return(self):
# bpo-36880: test that returning None from a py_object callback
# does not decrement the refcount of None.
for FUNCTYPE in (ctypes.CFUNCTYPE, ctypes.PYFUNCTYPE):
with self.subTest(FUNCTYPE=FUNCTYPE):
@FUNCTYPE(ctypes.py_object)
def func():
return None
# Check that calling func does not affect None's refcount.
for _ in range(10000):
func()
if __name__ == '__main__':
unittest.main()

29
Lib/ctypes/test/test_repr.py vendored Normal file
View File

@@ -0,0 +1,29 @@
from ctypes import *
import unittest
subclasses = []
for base in [c_byte, c_short, c_int, c_long, c_longlong,
c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong,
c_float, c_double, c_longdouble, c_bool]:
class X(base):
pass
subclasses.append(X)
class X(c_char):
pass
# This test checks if the __repr__ is correct for subclasses of simple types
class ReprTest(unittest.TestCase):
def test_numbers(self):
for typ in subclasses:
base = typ.__bases__[0]
self.assertTrue(repr(base(42)).startswith(base.__name__))
self.assertEqual("<X object at", repr(typ(42))[:12])
def test_char(self):
self.assertEqual("c_char(b'x')", repr(c_char(b'x')))
self.assertEqual("<X object at", repr(X(b'x'))[:12])
if __name__ == "__main__":
unittest.main()

66
Lib/ctypes/test/test_returnfuncptrs.py vendored Normal file
View File

@@ -0,0 +1,66 @@
import unittest
from ctypes import *
import _ctypes_test
class ReturnFuncPtrTestCase(unittest.TestCase):
def test_with_prototype(self):
# The _ctypes_test shared lib/dll exports quite some functions for testing.
# The get_strchr function returns a *pointer* to the C strchr function.
dll = CDLL(_ctypes_test.__file__)
get_strchr = dll.get_strchr
get_strchr.restype = CFUNCTYPE(c_char_p, c_char_p, c_char)
strchr = get_strchr()
self.assertEqual(strchr(b"abcdef", b"b"), b"bcdef")
self.assertEqual(strchr(b"abcdef", b"x"), None)
self.assertEqual(strchr(b"abcdef", 98), b"bcdef")
self.assertEqual(strchr(b"abcdef", 107), None)
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
self.assertRaises(TypeError, strchr, b"abcdef")
def test_without_prototype(self):
dll = CDLL(_ctypes_test.__file__)
get_strchr = dll.get_strchr
# the default 'c_int' would not work on systems where sizeof(int) != sizeof(void *)
get_strchr.restype = c_void_p
addr = get_strchr()
# _CFuncPtr instances are now callable with an integer argument
# which denotes a function address:
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(addr)
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
self.assertEqual(strchr(b"abcdef", b"x"), None)
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
self.assertRaises(TypeError, strchr, b"abcdef")
def test_from_dll(self):
dll = CDLL(_ctypes_test.__file__)
# _CFuncPtr instances are now callable with a tuple argument
# which denotes a function name and a dll:
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll))
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
self.assertEqual(strchr(b"abcdef", b"x"), None)
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
self.assertRaises(TypeError, strchr, b"abcdef")
# Issue 6083: Reference counting bug
def test_from_dll_refcount(self):
class BadSequence(tuple):
def __getitem__(self, key):
if key == 0:
return "my_strchr"
if key == 1:
return CDLL(_ctypes_test.__file__)
raise IndexError
# _CFuncPtr instances are now callable with a tuple argument
# which denotes a function name and a dll:
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(
BadSequence(("my_strchr", CDLL(_ctypes_test.__file__))))
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
self.assertEqual(strchr(b"abcdef", b"x"), None)
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
self.assertRaises(TypeError, strchr, b"abcdef")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,55 @@
import unittest
from ctypes import *
class MyInt(c_int):
def __eq__(self, other):
if type(other) != MyInt:
return NotImplementedError
return self.value == other.value
class Test(unittest.TestCase):
def test_compare(self):
self.assertEqual(MyInt(3), MyInt(3))
self.assertNotEqual(MyInt(42), MyInt(43))
def test_ignore_retval(self):
# Test if the return value of a callback is ignored
# if restype is None
proto = CFUNCTYPE(None)
def func():
return (1, "abc", None)
cb = proto(func)
self.assertEqual(None, cb())
def test_int_callback(self):
args = []
def func(arg):
args.append(arg)
return arg
cb = CFUNCTYPE(None, MyInt)(func)
self.assertEqual(None, cb(42))
self.assertEqual(type(args[-1]), MyInt)
cb = CFUNCTYPE(c_int, c_int)(func)
self.assertEqual(42, cb(42))
self.assertEqual(type(args[-1]), int)
def test_int_struct(self):
class X(Structure):
_fields_ = [("x", MyInt)]
self.assertEqual(X().x, MyInt())
s = X()
s.x = MyInt(42)
self.assertEqual(s.x, MyInt(42))
if __name__ == "__main__":
unittest.main()

33
Lib/ctypes/test/test_sizes.py vendored Normal file
View File

@@ -0,0 +1,33 @@
# Test specifically-sized containers.
from ctypes import *
import unittest
class SizesTestCase(unittest.TestCase):
def test_8(self):
self.assertEqual(1, sizeof(c_int8))
self.assertEqual(1, sizeof(c_uint8))
def test_16(self):
self.assertEqual(2, sizeof(c_int16))
self.assertEqual(2, sizeof(c_uint16))
def test_32(self):
self.assertEqual(4, sizeof(c_int32))
self.assertEqual(4, sizeof(c_uint32))
def test_64(self):
self.assertEqual(8, sizeof(c_int64))
self.assertEqual(8, sizeof(c_uint64))
def test_size_t(self):
self.assertEqual(sizeof(c_void_p), sizeof(c_size_t))
def test_ssize_t(self):
self.assertEqual(sizeof(c_void_p), sizeof(c_ssize_t))
if __name__ == "__main__":
unittest.main()

167
Lib/ctypes/test/test_slicing.py vendored Normal file
View File

@@ -0,0 +1,167 @@
import unittest
from ctypes import *
from ctypes.test import need_symbol
import _ctypes_test
class SlicesTestCase(unittest.TestCase):
def test_getslice_cint(self):
a = (c_int * 100)(*range(1100, 1200))
b = list(range(1100, 1200))
self.assertEqual(a[0:2], b[0:2])
self.assertEqual(a[0:2:], b[0:2:])
self.assertEqual(len(a), len(b))
self.assertEqual(a[5:7], b[5:7])
self.assertEqual(a[5:7:], b[5:7:])
self.assertEqual(a[-1], b[-1])
self.assertEqual(a[:], b[:])
self.assertEqual(a[::], b[::])
self.assertEqual(a[10::-1], b[10::-1])
self.assertEqual(a[30:20:-1], b[30:20:-1])
self.assertEqual(a[:12:6], b[:12:6])
self.assertEqual(a[2:6:4], b[2:6:4])
a[0:5] = range(5, 10)
self.assertEqual(a[0:5], list(range(5, 10)))
self.assertEqual(a[0:5:], list(range(5, 10)))
self.assertEqual(a[4::-1], list(range(9, 4, -1)))
def test_setslice_cint(self):
a = (c_int * 100)(*range(1100, 1200))
b = list(range(1100, 1200))
a[32:47] = list(range(32, 47))
self.assertEqual(a[32:47], list(range(32, 47)))
a[32:47] = range(132, 147)
self.assertEqual(a[32:47:], list(range(132, 147)))
a[46:31:-1] = range(232, 247)
self.assertEqual(a[32:47:1], list(range(246, 231, -1)))
a[32:47] = range(1132, 1147)
self.assertEqual(a[:], b)
a[32:47:7] = range(3)
b[32:47:7] = range(3)
self.assertEqual(a[:], b)
a[33::-3] = range(12)
b[33::-3] = range(12)
self.assertEqual(a[:], b)
from operator import setitem
# TypeError: int expected instead of str instance
self.assertRaises(TypeError, setitem, a, slice(0, 5), "abcde")
# TypeError: int expected instead of str instance
self.assertRaises(TypeError, setitem, a, slice(0, 5),
["a", "b", "c", "d", "e"])
# TypeError: int expected instead of float instance
self.assertRaises(TypeError, setitem, a, slice(0, 5),
[1, 2, 3, 4, 3.14])
# ValueError: Can only assign sequence of same size
self.assertRaises(ValueError, setitem, a, slice(0, 5), range(32))
def test_char_ptr(self):
s = b"abcdefghijklmnopqrstuvwxyz"
dll = CDLL(_ctypes_test.__file__)
dll.my_strdup.restype = POINTER(c_char)
dll.my_free.restype = None
res = dll.my_strdup(s)
self.assertEqual(res[:len(s)], s)
self.assertEqual(res[:3], s[:3])
self.assertEqual(res[:len(s):], s)
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])
self.assertEqual(res[0:-1:-1], s[0::-1])
import operator
self.assertRaises(ValueError, operator.getitem,
res, slice(None, None, None))
self.assertRaises(ValueError, operator.getitem,
res, slice(0, None, None))
self.assertRaises(ValueError, operator.getitem,
res, slice(None, 5, -1))
self.assertRaises(ValueError, operator.getitem,
res, slice(-5, None, None))
self.assertRaises(TypeError, operator.setitem,
res, slice(0, 5), "abcde")
dll.my_free(res)
dll.my_strdup.restype = POINTER(c_byte)
res = dll.my_strdup(s)
self.assertEqual(res[:len(s)], list(range(ord("a"), ord("z")+1)))
self.assertEqual(res[:len(s):], list(range(ord("a"), ord("z")+1)))
dll.my_free(res)
def test_char_ptr_with_free(self):
dll = CDLL(_ctypes_test.__file__)
s = b"abcdefghijklmnopqrstuvwxyz"
class allocated_c_char_p(c_char_p):
pass
dll.my_free.restype = None
def errcheck(result, func, args):
retval = result.value
dll.my_free(result)
return retval
dll.my_strdup.restype = allocated_c_char_p
dll.my_strdup.errcheck = errcheck
try:
res = dll.my_strdup(s)
self.assertEqual(res, s)
finally:
del dll.my_strdup.errcheck
def test_char_array(self):
s = b"abcdefghijklmnopqrstuvwxyz\0"
p = (c_char * 27)(*s)
self.assertEqual(p[:], s)
self.assertEqual(p[::], s)
self.assertEqual(p[::-1], s[::-1])
self.assertEqual(p[5::-2], s[5::-2])
self.assertEqual(p[2:5:-3], s[2:5:-3])
@need_symbol('c_wchar')
def test_wchar_ptr(self):
s = "abcdefghijklmnopqrstuvwxyz\0"
dll = CDLL(_ctypes_test.__file__)
dll.my_wcsdup.restype = POINTER(c_wchar)
dll.my_wcsdup.argtypes = POINTER(c_wchar),
dll.my_free.restype = None
res = dll.my_wcsdup(s[:-1])
self.assertEqual(res[:len(s)], s)
self.assertEqual(res[:len(s):], s)
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
self.assertEqual(res[len(s)-1:5:-7], s[:5:-7])
import operator
self.assertRaises(TypeError, operator.setitem,
res, slice(0, 5), "abcde")
dll.my_free(res)
if sizeof(c_wchar) == sizeof(c_short):
dll.my_wcsdup.restype = POINTER(c_short)
elif sizeof(c_wchar) == sizeof(c_int):
dll.my_wcsdup.restype = POINTER(c_int)
elif sizeof(c_wchar) == sizeof(c_long):
dll.my_wcsdup.restype = POINTER(c_long)
else:
self.skipTest('Pointers to c_wchar are not supported')
res = dll.my_wcsdup(s[:-1])
tmpl = list(range(ord("a"), ord("z")+1))
self.assertEqual(res[:len(s)-1], tmpl)
self.assertEqual(res[:len(s)-1:], tmpl)
self.assertEqual(res[len(s)-2:-1:-1], tmpl[::-1])
self.assertEqual(res[len(s)-2:5:-7], tmpl[:5:-7])
dll.my_free(res)
################################################################
if __name__ == "__main__":
unittest.main()

77
Lib/ctypes/test/test_stringptr.py vendored Normal file
View File

@@ -0,0 +1,77 @@
import unittest
from test import support
from ctypes import *
import _ctypes_test
lib = CDLL(_ctypes_test.__file__)
class StringPtrTestCase(unittest.TestCase):
@support.refcount_test
def test__POINTER_c_char(self):
class X(Structure):
_fields_ = [("str", POINTER(c_char))]
x = X()
# NULL pointer access
self.assertRaises(ValueError, getattr, x.str, "contents")
b = c_buffer(b"Hello, World")
from sys import getrefcount as grc
self.assertEqual(grc(b), 2)
x.str = b
self.assertEqual(grc(b), 3)
# POINTER(c_char) and Python string is NOT compatible
# POINTER(c_char) and c_buffer() is compatible
for i in range(len(b)):
self.assertEqual(b[i], x.str[i])
self.assertRaises(TypeError, setattr, x, "str", "Hello, World")
def test__c_char_p(self):
class X(Structure):
_fields_ = [("str", c_char_p)]
x = X()
# c_char_p and Python string is compatible
# c_char_p and c_buffer is NOT compatible
self.assertEqual(x.str, None)
x.str = b"Hello, World"
self.assertEqual(x.str, b"Hello, World")
b = c_buffer(b"Hello, World")
self.assertRaises(TypeError, setattr, x, b"str", b)
def test_functions(self):
strchr = lib.my_strchr
strchr.restype = c_char_p
# c_char_p and Python string is compatible
# c_char_p and c_buffer are now compatible
strchr.argtypes = c_char_p, c_char
self.assertEqual(strchr(b"abcdef", b"c"), b"cdef")
self.assertEqual(strchr(c_buffer(b"abcdef"), b"c"), b"cdef")
# POINTER(c_char) and Python string is NOT compatible
# POINTER(c_char) and c_buffer() is compatible
strchr.argtypes = POINTER(c_char), c_char
buf = c_buffer(b"abcdef")
self.assertEqual(strchr(buf, b"c"), b"cdef")
self.assertEqual(strchr(b"abcdef", b"c"), b"cdef")
# XXX These calls are dangerous, because the first argument
# to strchr is no longer valid after the function returns!
# So we must keep a reference to buf separately
strchr.restype = POINTER(c_char)
buf = c_buffer(b"abcdef")
r = strchr(buf, b"c")
x = r[0], r[1], r[2], r[3], r[4]
self.assertEqual(x, (b"c", b"d", b"e", b"f", b"\000"))
del buf
# Because r is a pointer to memory that is freed after deleting buf,
# the pointer is hanging and using it would reference freed memory.
if __name__ == '__main__':
unittest.main()

145
Lib/ctypes/test/test_strings.py vendored Normal file
View File

@@ -0,0 +1,145 @@
import unittest
from ctypes import *
from ctypes.test import need_symbol
class StringArrayTestCase(unittest.TestCase):
def test(self):
BUF = c_char * 4
buf = BUF(b"a", b"b", b"c")
self.assertEqual(buf.value, b"abc")
self.assertEqual(buf.raw, b"abc\000")
buf.value = b"ABCD"
self.assertEqual(buf.value, b"ABCD")
self.assertEqual(buf.raw, b"ABCD")
buf.value = b"x"
self.assertEqual(buf.value, b"x")
self.assertEqual(buf.raw, b"x\000CD")
buf[1] = b"Z"
self.assertEqual(buf.value, b"xZCD")
self.assertEqual(buf.raw, b"xZCD")
self.assertRaises(ValueError, setattr, buf, "value", b"aaaaaaaa")
self.assertRaises(TypeError, setattr, buf, "value", 42)
def test_c_buffer_value(self):
buf = c_buffer(32)
buf.value = b"Hello, World"
self.assertEqual(buf.value, b"Hello, World")
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"Hello, World"))
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"abc"))
self.assertRaises(ValueError, setattr, buf, "raw", memoryview(b"x" * 100))
def test_c_buffer_raw(self):
buf = c_buffer(32)
buf.raw = memoryview(b"Hello, World")
self.assertEqual(buf.value, b"Hello, World")
self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"abc"))
self.assertRaises(ValueError, setattr, buf, "raw", memoryview(b"x" * 100))
def test_param_1(self):
BUF = c_char * 4
buf = BUF()
## print c_char_p.from_param(buf)
def test_param_2(self):
BUF = c_char * 4
buf = BUF()
## print BUF.from_param(c_char_p("python"))
## print BUF.from_param(BUF(*"pyth"))
def test_del_segfault(self):
BUF = c_char * 4
buf = BUF()
with self.assertRaises(AttributeError):
del buf.raw
@need_symbol('c_wchar')
class WStringArrayTestCase(unittest.TestCase):
def test(self):
BUF = c_wchar * 4
buf = BUF("a", "b", "c")
self.assertEqual(buf.value, "abc")
buf.value = "ABCD"
self.assertEqual(buf.value, "ABCD")
buf.value = "x"
self.assertEqual(buf.value, "x")
buf[1] = "Z"
self.assertEqual(buf.value, "xZCD")
@unittest.skipIf(sizeof(c_wchar) < 4,
"sizeof(wchar_t) is smaller than 4 bytes")
def test_nonbmp(self):
u = chr(0x10ffff)
w = c_wchar(u)
self.assertEqual(w.value, u)
@need_symbol('c_wchar')
class WStringTestCase(unittest.TestCase):
def test_wchar(self):
c_wchar("x")
repr(byref(c_wchar("x")))
c_wchar("x")
@unittest.skip('test disabled')
def test_basic_wstrings(self):
cs = c_wstring("abcdef")
# XXX This behaviour is about to change:
# len returns the size of the internal buffer in bytes.
# This includes the terminating NUL character.
self.assertEqual(sizeof(cs), 14)
# The value property is the string up to the first terminating NUL.
self.assertEqual(cs.value, "abcdef")
self.assertEqual(c_wstring("abc\000def").value, "abc")
self.assertEqual(c_wstring("abc\000def").value, "abc")
# The raw property is the total buffer contents:
self.assertEqual(cs.raw, "abcdef\000")
self.assertEqual(c_wstring("abc\000def").raw, "abc\000def\000")
# We can change the value:
cs.value = "ab"
self.assertEqual(cs.value, "ab")
self.assertEqual(cs.raw, "ab\000\000\000\000\000")
self.assertRaises(TypeError, c_wstring, "123")
self.assertRaises(ValueError, c_wstring, 0)
@unittest.skip('test disabled')
def test_toolong(self):
cs = c_wstring("abcdef")
# Much too long string:
self.assertRaises(ValueError, setattr, cs, "value", "123456789012345")
# One char too long values:
self.assertRaises(ValueError, setattr, cs, "value", "1234567")
def run_test(rep, msg, func, arg):
items = range(rep)
from time import perf_counter as clock
start = clock()
for i in items:
func(arg); func(arg); func(arg); func(arg); func(arg)
stop = clock()
print("%20s: %.2f us" % (msg, ((stop-start)*1e6/5/rep)))
if __name__ == '__main__':
unittest.main()

97
Lib/ctypes/test/test_struct_fields.py vendored Normal file
View File

@@ -0,0 +1,97 @@
import unittest
from ctypes import *
class StructFieldsTestCase(unittest.TestCase):
# Structure/Union classes must get 'finalized' sooner or
# later, when one of these things happen:
#
# 1. _fields_ is set.
# 2. An instance is created.
# 3. The type is used as field of another Structure/Union.
# 4. The type is subclassed
#
# When they are finalized, assigning _fields_ is no longer allowed.
def test_1_A(self):
class X(Structure):
pass
self.assertEqual(sizeof(X), 0) # not finalized
X._fields_ = [] # finalized
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
def test_1_B(self):
class X(Structure):
_fields_ = [] # finalized
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
def test_2(self):
class X(Structure):
pass
X()
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
def test_3(self):
class X(Structure):
pass
class Y(Structure):
_fields_ = [("x", X)] # finalizes X
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
def test_4(self):
class X(Structure):
pass
class Y(X):
pass
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
Y._fields_ = []
self.assertRaises(AttributeError, setattr, X, "_fields_", [])
def test_5(self):
class X(Structure):
_fields_ = (("char", c_char * 5),)
x = X(b'#' * 5)
x.char = b'a\0b\0'
self.assertEqual(bytes(x), b'a\x00###')
def test_6(self):
class X(Structure):
_fields_ = [("x", c_int)]
CField = type(X.x)
self.assertRaises(TypeError, CField)
def test_gh99275(self):
class BrokenStructure(Structure):
def __init_subclass__(cls, **kwargs):
cls._fields_ = [] # This line will fail, `stgdict` is not ready
with self.assertRaisesRegex(TypeError,
'ctypes state is not initialized'):
class Subclass(BrokenStructure): ...
# __set__ and __get__ should raise a TypeError in case their self
# argument is not a ctype instance.
def test___set__(self):
class MyCStruct(Structure):
_fields_ = (("field", c_int),)
self.assertRaises(TypeError,
MyCStruct.field.__set__, 'wrong type self', 42)
class MyCUnion(Union):
_fields_ = (("field", c_int),)
self.assertRaises(TypeError,
MyCUnion.field.__set__, 'wrong type self', 42)
def test___get__(self):
class MyCStruct(Structure):
_fields_ = (("field", c_int),)
self.assertRaises(TypeError,
MyCStruct.field.__get__, 'wrong type self', 42)
class MyCUnion(Union):
_fields_ = (("field", c_int),)
self.assertRaises(TypeError,
MyCUnion.field.__get__, 'wrong type self', 42)
if __name__ == "__main__":
unittest.main()

812
Lib/ctypes/test/test_structures.py vendored Normal file
View File

@@ -0,0 +1,812 @@
import platform
import sys
import unittest
from ctypes import *
from ctypes.test import need_symbol
from struct import calcsize
import _ctypes_test
from test import support
# The following definition is meant to be used from time to time to assist
# temporarily disabling tests on specific architectures while investigations
# are in progress, to keep buildbots happy.
MACHINE = platform.machine()
class SubclassesTest(unittest.TestCase):
def test_subclass(self):
class X(Structure):
_fields_ = [("a", c_int)]
class Y(X):
_fields_ = [("b", c_int)]
class Z(X):
pass
self.assertEqual(sizeof(X), sizeof(c_int))
self.assertEqual(sizeof(Y), sizeof(c_int)*2)
self.assertEqual(sizeof(Z), sizeof(c_int))
self.assertEqual(X._fields_, [("a", c_int)])
self.assertEqual(Y._fields_, [("b", c_int)])
self.assertEqual(Z._fields_, [("a", c_int)])
def test_subclass_delayed(self):
class X(Structure):
pass
self.assertEqual(sizeof(X), 0)
X._fields_ = [("a", c_int)]
class Y(X):
pass
self.assertEqual(sizeof(Y), sizeof(X))
Y._fields_ = [("b", c_int)]
class Z(X):
pass
self.assertEqual(sizeof(X), sizeof(c_int))
self.assertEqual(sizeof(Y), sizeof(c_int)*2)
self.assertEqual(sizeof(Z), sizeof(c_int))
self.assertEqual(X._fields_, [("a", c_int)])
self.assertEqual(Y._fields_, [("b", c_int)])
self.assertEqual(Z._fields_, [("a", c_int)])
class StructureTestCase(unittest.TestCase):
formats = {"c": c_char,
"b": c_byte,
"B": c_ubyte,
"h": c_short,
"H": c_ushort,
"i": c_int,
"I": c_uint,
"l": c_long,
"L": c_ulong,
"q": c_longlong,
"Q": c_ulonglong,
"f": c_float,
"d": c_double,
}
def test_simple_structs(self):
for code, tp in self.formats.items():
class X(Structure):
_fields_ = [("x", c_char),
("y", tp)]
self.assertEqual((sizeof(X), code),
(calcsize("c%c0%c" % (code, code)), code))
def test_unions(self):
for code, tp in self.formats.items():
class X(Union):
_fields_ = [("x", c_char),
("y", tp)]
self.assertEqual((sizeof(X), code),
(calcsize("%c" % (code)), code))
def test_struct_alignment(self):
class X(Structure):
_fields_ = [("x", c_char * 3)]
self.assertEqual(alignment(X), calcsize("s"))
self.assertEqual(sizeof(X), calcsize("3s"))
class Y(Structure):
_fields_ = [("x", c_char * 3),
("y", c_int)]
self.assertEqual(alignment(Y), alignment(c_int))
self.assertEqual(sizeof(Y), calcsize("3si"))
class SI(Structure):
_fields_ = [("a", X),
("b", Y)]
self.assertEqual(alignment(SI), max(alignment(Y), alignment(X)))
self.assertEqual(sizeof(SI), calcsize("3s0i 3si 0i"))
class IS(Structure):
_fields_ = [("b", Y),
("a", X)]
self.assertEqual(alignment(SI), max(alignment(X), alignment(Y)))
self.assertEqual(sizeof(IS), calcsize("3si 3s 0i"))
class XX(Structure):
_fields_ = [("a", X),
("b", X)]
self.assertEqual(alignment(XX), alignment(X))
self.assertEqual(sizeof(XX), calcsize("3s 3s 0s"))
def test_empty(self):
# I had problems with these
#
# Although these are pathological cases: Empty Structures!
class X(Structure):
_fields_ = []
class Y(Union):
_fields_ = []
# Is this really the correct alignment, or should it be 0?
self.assertTrue(alignment(X) == alignment(Y) == 1)
self.assertTrue(sizeof(X) == sizeof(Y) == 0)
class XX(Structure):
_fields_ = [("a", X),
("b", X)]
self.assertEqual(alignment(XX), 1)
self.assertEqual(sizeof(XX), 0)
def test_fields(self):
# test the offset and size attributes of Structure/Union fields.
class X(Structure):
_fields_ = [("x", c_int),
("y", c_char)]
self.assertEqual(X.x.offset, 0)
self.assertEqual(X.x.size, sizeof(c_int))
self.assertEqual(X.y.offset, sizeof(c_int))
self.assertEqual(X.y.size, sizeof(c_char))
# readonly
self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)
self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)
class X(Union):
_fields_ = [("x", c_int),
("y", c_char)]
self.assertEqual(X.x.offset, 0)
self.assertEqual(X.x.size, sizeof(c_int))
self.assertEqual(X.y.offset, 0)
self.assertEqual(X.y.size, sizeof(c_char))
# readonly
self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)
self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)
# XXX Should we check nested data types also?
# offset is always relative to the class...
def test_packed(self):
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 1
self.assertEqual(sizeof(X), 9)
self.assertEqual(X.b.offset, 1)
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 2
self.assertEqual(sizeof(X), 10)
self.assertEqual(X.b.offset, 2)
import struct
longlong_size = struct.calcsize("q")
longlong_align = struct.calcsize("bq") - longlong_size
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 4
self.assertEqual(sizeof(X), min(4, longlong_align) + longlong_size)
self.assertEqual(X.b.offset, min(4, longlong_align))
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 8
self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size)
self.assertEqual(X.b.offset, min(8, longlong_align))
d = {"_fields_": [("a", "b"),
("b", "q")],
"_pack_": -1}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
@support.cpython_only
def test_packed_c_limits(self):
# Issue 15989
import _testcapi
d = {"_fields_": [("a", c_byte)],
"_pack_": _testcapi.INT_MAX + 1}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
d = {"_fields_": [("a", c_byte)],
"_pack_": _testcapi.UINT_MAX + 2}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
def test_initializers(self):
class Person(Structure):
_fields_ = [("name", c_char*6),
("age", c_int)]
self.assertRaises(TypeError, Person, 42)
self.assertRaises(ValueError, Person, b"asldkjaslkdjaslkdj")
self.assertRaises(TypeError, Person, "Name", "HI")
# short enough
self.assertEqual(Person(b"12345", 5).name, b"12345")
# exact fit
self.assertEqual(Person(b"123456", 5).name, b"123456")
# too long
self.assertRaises(ValueError, Person, b"1234567", 5)
def test_conflicting_initializers(self):
class POINT(Structure):
_fields_ = [("phi", c_float), ("rho", c_float)]
# conflicting positional and keyword args
self.assertRaisesRegex(TypeError, "phi", POINT, 2, 3, phi=4)
self.assertRaisesRegex(TypeError, "rho", POINT, 2, 3, rho=4)
# too many initializers
self.assertRaises(TypeError, POINT, 2, 3, 4)
def test_keyword_initializers(self):
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
pt = POINT(1, 2)
self.assertEqual((pt.x, pt.y), (1, 2))
pt = POINT(y=2, x=1)
self.assertEqual((pt.x, pt.y), (1, 2))
def test_invalid_field_types(self):
class POINT(Structure):
pass
self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)])
def test_invalid_name(self):
# field name must be string
def declare_with_name(name):
class S(Structure):
_fields_ = [(name, c_int)]
self.assertRaises(TypeError, declare_with_name, b"x")
def test_intarray_fields(self):
class SomeInts(Structure):
_fields_ = [("a", c_int * 4)]
# can use tuple to initialize array (but not list!)
self.assertEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0])
self.assertEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0])
self.assertEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1])
self.assertEqual(SomeInts((1, 2)).a[::2], [1, 0])
self.assertEqual(SomeInts((1, 2)).a[1:5:6], [2])
self.assertEqual(SomeInts((1, 2)).a[6:4:-1], [])
self.assertEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4])
self.assertEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4])
# too long
# XXX Should raise ValueError?, not RuntimeError
self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5))
def test_nested_initializers(self):
# test initializing nested structures
class Phone(Structure):
_fields_ = [("areacode", c_char*6),
("number", c_char*12)]
class Person(Structure):
_fields_ = [("name", c_char * 12),
("phone", Phone),
("age", c_int)]
p = Person(b"Someone", (b"1234", b"5678"), 5)
self.assertEqual(p.name, b"Someone")
self.assertEqual(p.phone.areacode, b"1234")
self.assertEqual(p.phone.number, b"5678")
self.assertEqual(p.age, 5)
@need_symbol('c_wchar')
def test_structures_with_wchar(self):
class PersonW(Structure):
_fields_ = [("name", c_wchar * 12),
("age", c_int)]
p = PersonW("Someone \xe9")
self.assertEqual(p.name, "Someone \xe9")
self.assertEqual(PersonW("1234567890").name, "1234567890")
self.assertEqual(PersonW("12345678901").name, "12345678901")
# exact fit
self.assertEqual(PersonW("123456789012").name, "123456789012")
#too long
self.assertRaises(ValueError, PersonW, "1234567890123")
def test_init_errors(self):
class Phone(Structure):
_fields_ = [("areacode", c_char*6),
("number", c_char*12)]
class Person(Structure):
_fields_ = [("name", c_char * 12),
("phone", Phone),
("age", c_int)]
cls, msg = self.get_except(Person, b"Someone", (1, 2))
self.assertEqual(cls, RuntimeError)
self.assertEqual(msg,
"(Phone) TypeError: "
"expected bytes, int found")
cls, msg = self.get_except(Person, b"Someone", (b"a", b"b", b"c"))
self.assertEqual(cls, RuntimeError)
self.assertEqual(msg,
"(Phone) TypeError: too many initializers")
def test_huge_field_name(self):
# issue12881: segfault with large structure field names
def create_class(length):
class S(Structure):
_fields_ = [('x' * length, c_int)]
for length in [10 ** i for i in range(0, 8)]:
try:
create_class(length)
except MemoryError:
# MemoryErrors are OK, we just don't want to segfault
pass
def get_except(self, func, *args):
try:
func(*args)
except Exception as detail:
return detail.__class__, str(detail)
@unittest.skip('test disabled')
def test_subclass_creation(self):
meta = type(Structure)
# same as 'class X(Structure): pass'
# fails, since we need either a _fields_ or a _abstract_ attribute
cls, msg = self.get_except(meta, "X", (Structure,), {})
self.assertEqual((cls, msg),
(AttributeError, "class must define a '_fields_' attribute"))
def test_abstract_class(self):
class X(Structure):
_abstract_ = "something"
# try 'X()'
cls, msg = self.get_except(eval, "X()", locals())
self.assertEqual((cls, msg), (TypeError, "abstract class"))
def test_methods(self):
## class X(Structure):
## _fields_ = []
self.assertIn("in_dll", dir(type(Structure)))
self.assertIn("from_address", dir(type(Structure)))
self.assertIn("in_dll", dir(type(Structure)))
def test_positional_args(self):
# see also http://bugs.python.org/issue5042
class W(Structure):
_fields_ = [("a", c_int), ("b", c_int)]
class X(W):
_fields_ = [("c", c_int)]
class Y(X):
pass
class Z(Y):
_fields_ = [("d", c_int), ("e", c_int), ("f", c_int)]
z = Z(1, 2, 3, 4, 5, 6)
self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f),
(1, 2, 3, 4, 5, 6))
z = Z(1)
self.assertEqual((z.a, z.b, z.c, z.d, z.e, z.f),
(1, 0, 0, 0, 0, 0))
self.assertRaises(TypeError, lambda: Z(1, 2, 3, 4, 5, 6, 7))
def test_pass_by_value(self):
# This should mirror the Test structure
# in Modules/_ctypes/_ctypes_test.c
class Test(Structure):
_fields_ = [
('first', c_ulong),
('second', c_ulong),
('third', c_ulong),
]
s = Test()
s.first = 0xdeadbeef
s.second = 0xcafebabe
s.third = 0x0bad1dea
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_large_struct_update_value
func.argtypes = (Test,)
func.restype = None
func(s)
self.assertEqual(s.first, 0xdeadbeef)
self.assertEqual(s.second, 0xcafebabe)
self.assertEqual(s.third, 0x0bad1dea)
def test_pass_by_value_finalizer(self):
# bpo-37140: Similar to test_pass_by_value(), but the Python structure
# has a finalizer (__del__() method): the finalizer must only be called
# once.
finalizer_calls = []
class Test(Structure):
_fields_ = [
('first', c_ulong),
('second', c_ulong),
('third', c_ulong),
]
def __del__(self):
finalizer_calls.append("called")
s = Test(1, 2, 3)
# Test the StructUnionType_paramfunc() code path which copies the
# structure: if the structure is larger than sizeof(void*).
self.assertGreater(sizeof(s), sizeof(c_void_p))
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_large_struct_update_value
func.argtypes = (Test,)
func.restype = None
func(s)
# bpo-37140: Passing the structure by reference must not call
# its finalizer!
self.assertEqual(finalizer_calls, [])
self.assertEqual(s.first, 1)
self.assertEqual(s.second, 2)
self.assertEqual(s.third, 3)
# The finalizer must be called exactly once
s = None
support.gc_collect()
self.assertEqual(finalizer_calls, ["called"])
def test_pass_by_value_in_register(self):
class X(Structure):
_fields_ = [
('first', c_uint),
('second', c_uint)
]
s = X()
s.first = 0xdeadbeef
s.second = 0xcafebabe
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_reg_struct_update_value
func.argtypes = (X,)
func.restype = None
func(s)
self.assertEqual(s.first, 0xdeadbeef)
self.assertEqual(s.second, 0xcafebabe)
got = X.in_dll(dll, "last_tfrsuv_arg")
self.assertEqual(s.first, got.first)
self.assertEqual(s.second, got.second)
def test_array_in_struct(self):
# See bpo-22273
# These should mirror the structures in Modules/_ctypes/_ctypes_test.c
class Test2(Structure):
_fields_ = [
('data', c_ubyte * 16),
]
class Test3(Structure):
_fields_ = [
('data', c_double * 2),
]
class Test3A(Structure):
_fields_ = [
('data', c_float * 2),
]
class Test3B(Test3A):
_fields_ = [
('more_data', c_float * 2),
]
s = Test2()
expected = 0
for i in range(16):
s.data[i] = i
expected += i
dll = CDLL(_ctypes_test.__file__)
func = dll._testfunc_array_in_struct1
func.restype = c_int
func.argtypes = (Test2,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
for i in range(16):
self.assertEqual(s.data[i], i)
s = Test3()
s.data[0] = 3.14159
s.data[1] = 2.71828
expected = 3.14159 + 2.71828
func = dll._testfunc_array_in_struct2
func.restype = c_double
func.argtypes = (Test3,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
self.assertEqual(s.data[0], 3.14159)
self.assertEqual(s.data[1], 2.71828)
s = Test3B()
s.data[0] = 3.14159
s.data[1] = 2.71828
s.more_data[0] = -3.0
s.more_data[1] = -2.0
expected = 3.14159 + 2.71828 - 5.0
func = dll._testfunc_array_in_struct2a
func.restype = c_double
func.argtypes = (Test3B,)
result = func(s)
self.assertAlmostEqual(result, expected, places=6)
# check the passed-in struct hasn't changed
self.assertAlmostEqual(s.data[0], 3.14159, places=6)
self.assertAlmostEqual(s.data[1], 2.71828, places=6)
self.assertAlmostEqual(s.more_data[0], -3.0, places=6)
self.assertAlmostEqual(s.more_data[1], -2.0, places=6)
def test_38368(self):
class U(Union):
_fields_ = [
('f1', c_uint8 * 16),
('f2', c_uint16 * 8),
('f3', c_uint32 * 4),
]
u = U()
u.f3[0] = 0x01234567
u.f3[1] = 0x89ABCDEF
u.f3[2] = 0x76543210
u.f3[3] = 0xFEDCBA98
f1 = [u.f1[i] for i in range(16)]
f2 = [u.f2[i] for i in range(8)]
if sys.byteorder == 'little':
self.assertEqual(f1, [0x67, 0x45, 0x23, 0x01,
0xef, 0xcd, 0xab, 0x89,
0x10, 0x32, 0x54, 0x76,
0x98, 0xba, 0xdc, 0xfe])
self.assertEqual(f2, [0x4567, 0x0123, 0xcdef, 0x89ab,
0x3210, 0x7654, 0xba98, 0xfedc])
@unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576')
def test_union_by_value(self):
# See bpo-16575
# These should mirror the structures in Modules/_ctypes/_ctypes_test.c
class Nested1(Structure):
_fields_ = [
('an_int', c_int),
('another_int', c_int),
]
class Test4(Union):
_fields_ = [
('a_long', c_long),
('a_struct', Nested1),
]
class Nested2(Structure):
_fields_ = [
('an_int', c_int),
('a_union', Test4),
]
class Test5(Structure):
_fields_ = [
('an_int', c_int),
('nested', Nested2),
('another_int', c_int),
]
test4 = Test4()
dll = CDLL(_ctypes_test.__file__)
with self.assertRaises(TypeError) as ctx:
func = dll._testfunc_union_by_value1
func.restype = c_long
func.argtypes = (Test4,)
result = func(test4)
self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes '
'a union by value, which is unsupported.')
test5 = Test5()
with self.assertRaises(TypeError) as ctx:
func = dll._testfunc_union_by_value2
func.restype = c_long
func.argtypes = (Test5,)
result = func(test5)
self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes '
'a union by value, which is unsupported.')
# passing by reference should be OK
test4.a_long = 12345;
func = dll._testfunc_union_by_reference1
func.restype = c_long
func.argtypes = (POINTER(Test4),)
result = func(byref(test4))
self.assertEqual(result, 12345)
self.assertEqual(test4.a_long, 0)
self.assertEqual(test4.a_struct.an_int, 0)
self.assertEqual(test4.a_struct.another_int, 0)
test4.a_struct.an_int = 0x12340000
test4.a_struct.another_int = 0x5678
func = dll._testfunc_union_by_reference2
func.restype = c_long
func.argtypes = (POINTER(Test4),)
result = func(byref(test4))
self.assertEqual(result, 0x12345678)
self.assertEqual(test4.a_long, 0)
self.assertEqual(test4.a_struct.an_int, 0)
self.assertEqual(test4.a_struct.another_int, 0)
test5.an_int = 0x12000000
test5.nested.an_int = 0x345600
test5.another_int = 0x78
func = dll._testfunc_union_by_reference3
func.restype = c_long
func.argtypes = (POINTER(Test5),)
result = func(byref(test5))
self.assertEqual(result, 0x12345678)
self.assertEqual(test5.an_int, 0)
self.assertEqual(test5.nested.an_int, 0)
self.assertEqual(test5.another_int, 0)
@unittest.skipIf(True, 'Test disabled for now - see bpo-16575/bpo-16576')
def test_bitfield_by_value(self):
# See bpo-16576
# These should mirror the structures in Modules/_ctypes/_ctypes_test.c
class Test6(Structure):
_fields_ = [
('A', c_int, 1),
('B', c_int, 2),
('C', c_int, 3),
('D', c_int, 2),
]
test6 = Test6()
# As these are signed int fields, all are logically -1 due to sign
# extension.
test6.A = 1
test6.B = 3
test6.C = 7
test6.D = 3
dll = CDLL(_ctypes_test.__file__)
with self.assertRaises(TypeError) as ctx:
func = dll._testfunc_bitfield_by_value1
func.restype = c_long
func.argtypes = (Test6,)
result = func(test6)
self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes '
'a struct/union with a bitfield by value, which is '
'unsupported.')
# passing by reference should be OK
func = dll._testfunc_bitfield_by_reference1
func.restype = c_long
func.argtypes = (POINTER(Test6),)
result = func(byref(test6))
self.assertEqual(result, -4)
self.assertEqual(test6.A, 0)
self.assertEqual(test6.B, 0)
self.assertEqual(test6.C, 0)
self.assertEqual(test6.D, 0)
class Test7(Structure):
_fields_ = [
('A', c_uint, 1),
('B', c_uint, 2),
('C', c_uint, 3),
('D', c_uint, 2),
]
test7 = Test7()
test7.A = 1
test7.B = 3
test7.C = 7
test7.D = 3
func = dll._testfunc_bitfield_by_reference2
func.restype = c_long
func.argtypes = (POINTER(Test7),)
result = func(byref(test7))
self.assertEqual(result, 14)
self.assertEqual(test7.A, 0)
self.assertEqual(test7.B, 0)
self.assertEqual(test7.C, 0)
self.assertEqual(test7.D, 0)
# for a union with bitfields, the union check happens first
class Test8(Union):
_fields_ = [
('A', c_int, 1),
('B', c_int, 2),
('C', c_int, 3),
('D', c_int, 2),
]
test8 = Test8()
with self.assertRaises(TypeError) as ctx:
func = dll._testfunc_bitfield_by_value2
func.restype = c_long
func.argtypes = (Test8,)
result = func(test8)
self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes '
'a union by value, which is unsupported.')
class PointerMemberTestCase(unittest.TestCase):
def test(self):
# a Structure with a POINTER field
class S(Structure):
_fields_ = [("array", POINTER(c_int))]
s = S()
# We can assign arrays of the correct type
s.array = (c_int * 3)(1, 2, 3)
items = [s.array[i] for i in range(3)]
self.assertEqual(items, [1, 2, 3])
# The following are bugs, but are included here because the unittests
# also describe the current behaviour.
#
# This fails with SystemError: bad arg to internal function
# or with IndexError (with a patch I have)
s.array[0] = 42
items = [s.array[i] for i in range(3)]
self.assertEqual(items, [42, 2, 3])
s.array[0] = 1
## s.array[1] = 42
items = [s.array[i] for i in range(3)]
self.assertEqual(items, [1, 2, 3])
def test_none_to_pointer_fields(self):
class S(Structure):
_fields_ = [("x", c_int),
("p", POINTER(c_int))]
s = S()
s.x = 12345678
s.p = None
self.assertEqual(s.x, 12345678)
class TestRecursiveStructure(unittest.TestCase):
def test_contains_itself(self):
class Recursive(Structure):
pass
try:
Recursive._fields_ = [("next", Recursive)]
except AttributeError as details:
self.assertIn("Structure or union cannot contain itself",
str(details))
else:
self.fail("Structure or union cannot contain itself")
def test_vice_versa(self):
class First(Structure):
pass
class Second(Structure):
pass
First._fields_ = [("second", Second)]
try:
Second._fields_ = [("first", First)]
except AttributeError as details:
self.assertIn("_fields_ is final", str(details))
else:
self.fail("AttributeError not raised")
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,43 @@
import sys, unittest
from ctypes import *
structures = []
byteswapped_structures = []
if sys.byteorder == "little":
SwappedStructure = BigEndianStructure
else:
SwappedStructure = LittleEndianStructure
for typ in [c_short, c_int, c_long, c_longlong,
c_float, c_double,
c_ushort, c_uint, c_ulong, c_ulonglong]:
class X(Structure):
_pack_ = 1
_fields_ = [("pad", c_byte),
("value", typ)]
class Y(SwappedStructure):
_pack_ = 1
_fields_ = [("pad", c_byte),
("value", typ)]
structures.append(X)
byteswapped_structures.append(Y)
class TestStructures(unittest.TestCase):
def test_native(self):
for typ in structures:
self.assertEqual(typ.value.offset, 1)
o = typ()
o.value = 4
self.assertEqual(o.value, 4)
def test_swapped(self):
for typ in byteswapped_structures:
self.assertEqual(typ.value.offset, 1)
o = typ()
o.value = 4
self.assertEqual(o.value, 4)
if __name__ == '__main__':
unittest.main()

64
Lib/ctypes/test/test_unicode.py vendored Normal file
View File

@@ -0,0 +1,64 @@
import unittest
import ctypes
from ctypes.test import need_symbol
import _ctypes_test
@need_symbol('c_wchar')
class UnicodeTestCase(unittest.TestCase):
def test_wcslen(self):
dll = ctypes.CDLL(_ctypes_test.__file__)
wcslen = dll.my_wcslen
wcslen.argtypes = [ctypes.c_wchar_p]
self.assertEqual(wcslen("abc"), 3)
self.assertEqual(wcslen("ab\u2070"), 3)
self.assertRaises(ctypes.ArgumentError, wcslen, b"ab\xe4")
def test_buffers(self):
buf = ctypes.create_unicode_buffer("abc")
self.assertEqual(len(buf), 3+1)
buf = ctypes.create_unicode_buffer("ab\xe4\xf6\xfc")
self.assertEqual(buf[:], "ab\xe4\xf6\xfc\0")
self.assertEqual(buf[::], "ab\xe4\xf6\xfc\0")
self.assertEqual(buf[::-1], '\x00\xfc\xf6\xe4ba')
self.assertEqual(buf[::2], 'a\xe4\xfc')
self.assertEqual(buf[6:5:-1], "")
def test_embedded_null(self):
class TestStruct(ctypes.Structure):
_fields_ = [("unicode", ctypes.c_wchar_p)]
t = TestStruct()
# This would raise a ValueError:
t.unicode = "foo\0bar\0\0"
func = ctypes.CDLL(_ctypes_test.__file__)._testfunc_p_p
class StringTestCase(UnicodeTestCase):
def setUp(self):
func.argtypes = [ctypes.c_char_p]
func.restype = ctypes.c_char_p
def tearDown(self):
func.argtypes = None
func.restype = ctypes.c_int
def test_func(self):
self.assertEqual(func(b"abc\xe4"), b"abc\xe4")
def test_buffers(self):
buf = ctypes.create_string_buffer(b"abc")
self.assertEqual(len(buf), 3+1)
buf = ctypes.create_string_buffer(b"ab\xe4\xf6\xfc")
self.assertEqual(buf[:], b"ab\xe4\xf6\xfc\0")
self.assertEqual(buf[::], b"ab\xe4\xf6\xfc\0")
self.assertEqual(buf[::-1], b'\x00\xfc\xf6\xe4ba')
self.assertEqual(buf[::2], b'a\xe4\xfc')
self.assertEqual(buf[6:5:-1], b"")
if __name__ == '__main__':
unittest.main()

103
Lib/ctypes/test/test_values.py vendored Normal file
View File

@@ -0,0 +1,103 @@
"""
A testcase which accesses *values* in a dll.
"""
import _imp
import importlib.util
import unittest
import sys
from ctypes import *
from test.support import import_helper
import _ctypes_test
class ValuesTestCase(unittest.TestCase):
def test_an_integer(self):
# This test checks and changes an integer stored inside the
# _ctypes_test dll/shared lib.
ctdll = CDLL(_ctypes_test.__file__)
an_integer = c_int.in_dll(ctdll, "an_integer")
x = an_integer.value
self.assertEqual(x, ctdll.get_an_integer())
an_integer.value *= 2
self.assertEqual(x*2, ctdll.get_an_integer())
# To avoid test failures when this test is repeated several
# times the original value must be restored
an_integer.value = x
self.assertEqual(x, ctdll.get_an_integer())
def test_undefined(self):
ctdll = CDLL(_ctypes_test.__file__)
self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol")
class PythonValuesTestCase(unittest.TestCase):
"""This test only works when python itself is a dll/shared library"""
def test_optimizeflag(self):
# This test accesses the Py_OptimizeFlag integer, which is
# exported by the Python dll and should match the sys.flags value
opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value
self.assertEqual(opt, sys.flags.optimize)
def test_frozentable(self):
# Python exports a PyImport_FrozenModules symbol. This is a
# pointer to an array of struct _frozen entries. The end of the
# array is marked by an entry containing a NULL name and zero
# size.
# In standard Python, this table contains a __hello__
# module, and a __phello__ package containing a spam
# module.
class struct_frozen(Structure):
_fields_ = [("name", c_char_p),
("code", POINTER(c_ubyte)),
("size", c_int),
("is_package", c_int),
("get_code", POINTER(c_ubyte)), # Function ptr
]
FrozenTable = POINTER(struct_frozen)
modules = []
for group in ["Bootstrap", "Stdlib", "Test"]:
ft = FrozenTable.in_dll(pythonapi, f"_PyImport_Frozen{group}")
# ft is a pointer to the struct_frozen entries:
for entry in ft:
# This is dangerous. We *can* iterate over a pointer, but
# the loop will not terminate (maybe with an access
# violation;-) because the pointer instance has no size.
if entry.name is None:
break
modname = entry.name.decode("ascii")
modules.append(modname)
with self.subTest(modname):
if entry.size != 0:
# Do a sanity check on entry.size and entry.code.
self.assertGreater(abs(entry.size), 10)
self.assertTrue([entry.code[i] for i in range(abs(entry.size))])
# Check the module's package-ness.
with import_helper.frozen_modules():
spec = importlib.util.find_spec(modname)
if entry.is_package:
# It's a package.
self.assertIsNotNone(spec.submodule_search_locations)
else:
self.assertIsNone(spec.submodule_search_locations)
with import_helper.frozen_modules():
expected = _imp._frozen_module_names()
self.maxDiff = None
self.assertEqual(modules, expected,
"_PyImport_FrozenBootstrap example "
"in Doc/library/ctypes.rst may be out of date")
from ctypes import _pointer_type_cache
del _pointer_type_cache[struct_frozen]
def test_undefined(self):
self.assertRaises(ValueError, c_int.in_dll, pythonapi,
"Undefined_Symbol")
if __name__ == '__main__':
unittest.main()

50
Lib/ctypes/test/test_varsize_struct.py vendored Normal file
View File

@@ -0,0 +1,50 @@
from ctypes import *
import unittest
class VarSizeTest(unittest.TestCase):
def test_resize(self):
class X(Structure):
_fields_ = [("item", c_int),
("array", c_int * 1)]
self.assertEqual(sizeof(X), sizeof(c_int) * 2)
x = X()
x.item = 42
x.array[0] = 100
self.assertEqual(sizeof(x), sizeof(c_int) * 2)
# make room for one additional item
new_size = sizeof(X) + sizeof(c_int) * 1
resize(x, new_size)
self.assertEqual(sizeof(x), new_size)
self.assertEqual((x.item, x.array[0]), (42, 100))
# make room for 10 additional items
new_size = sizeof(X) + sizeof(c_int) * 9
resize(x, new_size)
self.assertEqual(sizeof(x), new_size)
self.assertEqual((x.item, x.array[0]), (42, 100))
# make room for one additional item
new_size = sizeof(X) + sizeof(c_int) * 1
resize(x, new_size)
self.assertEqual(sizeof(x), new_size)
self.assertEqual((x.item, x.array[0]), (42, 100))
def test_array_invalid_length(self):
# cannot create arrays with non-positive size
self.assertRaises(ValueError, lambda: c_int * -1)
self.assertRaises(ValueError, lambda: c_int * -3)
def test_zerosized_array(self):
array = (c_int * 0)()
# accessing elements of zero-sized arrays raise IndexError
self.assertRaises(IndexError, array.__setitem__, 0, None)
self.assertRaises(IndexError, array.__getitem__, 0)
self.assertRaises(IndexError, array.__setitem__, 1, None)
self.assertRaises(IndexError, array.__getitem__, 1)
self.assertRaises(IndexError, array.__setitem__, -1, None)
self.assertRaises(IndexError, array.__getitem__, -1)
if __name__ == "__main__":
unittest.main()

136
Lib/ctypes/test/test_win32.py vendored Normal file
View File

@@ -0,0 +1,136 @@
# Windows specific tests
from ctypes import *
import unittest, sys
from test import support
import _ctypes_test
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class FunctionCallTestCase(unittest.TestCase):
@unittest.skipUnless('MSC' in sys.version, "SEH only supported by MSC")
@unittest.skipIf(sys.executable.lower().endswith('_d.exe'),
"SEH not enabled in debug builds")
def test_SEH(self):
# Disable faulthandler to prevent logging the warning:
# "Windows fatal exception: access violation"
with support.disable_faulthandler():
# Call functions with invalid arguments, and make sure
# that access violations are trapped and raise an
# exception.
self.assertRaises(OSError, windll.kernel32.GetModuleHandleA, 32)
def test_noargs(self):
# This is a special case on win32 x64
windll.user32.GetDesktopWindow()
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class ReturnStructSizesTestCase(unittest.TestCase):
def test_sizes(self):
dll = CDLL(_ctypes_test.__file__)
for i in range(1, 11):
fields = [ (f"f{f}", c_char) for f in range(1, i + 1)]
class S(Structure):
_fields_ = fields
f = getattr(dll, f"TestSize{i}")
f.restype = S
res = f()
for i, f in enumerate(fields):
value = getattr(res, f[0])
expected = bytes([ord('a') + i])
self.assertEqual(value, expected)
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class TestWintypes(unittest.TestCase):
def test_HWND(self):
from ctypes import wintypes
self.assertEqual(sizeof(wintypes.HWND), sizeof(c_void_p))
def test_PARAM(self):
from ctypes import wintypes
self.assertEqual(sizeof(wintypes.WPARAM),
sizeof(c_void_p))
self.assertEqual(sizeof(wintypes.LPARAM),
sizeof(c_void_p))
def test_COMError(self):
from _ctypes import COMError
if support.HAVE_DOCSTRINGS:
self.assertEqual(COMError.__doc__,
"Raised when a COM method call failed.")
ex = COMError(-1, "text", ("details",))
self.assertEqual(ex.hresult, -1)
self.assertEqual(ex.text, "text")
self.assertEqual(ex.details, ("details",))
@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
class TestWinError(unittest.TestCase):
def test_winerror(self):
# see Issue 16169
import errno
ERROR_INVALID_PARAMETER = 87
msg = FormatError(ERROR_INVALID_PARAMETER).strip()
args = (errno.EINVAL, msg, None, ERROR_INVALID_PARAMETER)
e = WinError(ERROR_INVALID_PARAMETER)
self.assertEqual(e.args, args)
self.assertEqual(e.errno, errno.EINVAL)
self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER)
windll.kernel32.SetLastError(ERROR_INVALID_PARAMETER)
try:
raise WinError()
except OSError as exc:
e = exc
self.assertEqual(e.args, args)
self.assertEqual(e.errno, errno.EINVAL)
self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER)
class Structures(unittest.TestCase):
def test_struct_by_value(self):
class POINT(Structure):
_fields_ = [("x", c_long),
("y", c_long)]
class RECT(Structure):
_fields_ = [("left", c_long),
("top", c_long),
("right", c_long),
("bottom", c_long)]
dll = CDLL(_ctypes_test.__file__)
pt = POINT(15, 25)
left = c_long.in_dll(dll, 'left')
top = c_long.in_dll(dll, 'top')
right = c_long.in_dll(dll, 'right')
bottom = c_long.in_dll(dll, 'bottom')
rect = RECT(left, top, right, bottom)
PointInRect = dll.PointInRect
PointInRect.argtypes = [POINTER(RECT), POINT]
self.assertEqual(1, PointInRect(byref(rect), pt))
ReturnRect = dll.ReturnRect
ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT,
POINTER(RECT), POINT, RECT]
ReturnRect.restype = RECT
for i in range(4):
ret = ReturnRect(i, rect, pointer(rect), pt, rect,
byref(rect), pt, rect)
# the c function will check and modify ret if something is
# passed in improperly
self.assertEqual(ret.left, left.value)
self.assertEqual(ret.right, right.value)
self.assertEqual(ret.top, top.value)
self.assertEqual(ret.bottom, bottom.value)
# to not leak references, we must clean _pointer_type_cache
from ctypes import _pointer_type_cache
del _pointer_type_cache[RECT]
if __name__ == '__main__':
unittest.main()

43
Lib/ctypes/test/test_wintypes.py vendored Normal file
View File

@@ -0,0 +1,43 @@
import unittest
# also work on POSIX
from ctypes import *
from ctypes import wintypes
class WinTypesTest(unittest.TestCase):
def test_variant_bool(self):
# reads 16-bits from memory, anything non-zero is True
for true_value in (1, 32767, 32768, 65535, 65537):
true = POINTER(c_int16)(c_int16(true_value))
value = cast(true, POINTER(wintypes.VARIANT_BOOL))
self.assertEqual(repr(value.contents), 'VARIANT_BOOL(True)')
vb = wintypes.VARIANT_BOOL()
self.assertIs(vb.value, False)
vb.value = True
self.assertIs(vb.value, True)
vb.value = true_value
self.assertIs(vb.value, True)
for false_value in (0, 65536, 262144, 2**33):
false = POINTER(c_int16)(c_int16(false_value))
value = cast(false, POINTER(wintypes.VARIANT_BOOL))
self.assertEqual(repr(value.contents), 'VARIANT_BOOL(False)')
# allow any bool conversion on assignment to value
for set_value in (65536, 262144, 2**33):
vb = wintypes.VARIANT_BOOL()
vb.value = set_value
self.assertIs(vb.value, True)
vb = wintypes.VARIANT_BOOL()
vb.value = [2, 3]
self.assertIs(vb.value, True)
vb.value = []
self.assertIs(vb.value, False)
if __name__ == "__main__":
unittest.main()

10
Lib/test/test_ctypes.py vendored Normal file
View File

@@ -0,0 +1,10 @@
import unittest
from test.support.import_helper import import_module
ctypes_test = import_module('ctypes.test')
load_tests = ctypes_test.load_tests
if __name__ == "__main__":
unittest.main()