blob: 5340f79fa94f1ac4ef154ace74c7da15ef8f2075 [file] [log] [blame]
import unittest
from ctypes import *
from struct import calcsize
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.failUnlessEqual(sizeof(X), sizeof(c_int))
self.failUnlessEqual(sizeof(Y), sizeof(c_int)*2)
self.failUnlessEqual(sizeof(Z), sizeof(c_int))
self.failUnlessEqual(X._fields_, [("a", c_int)])
self.failUnlessEqual(Y._fields_, [("b", c_int)])
self.failUnlessEqual(Z._fields_, [("a", c_int)])
def test_subclass_delayed(self):
class X(Structure):
pass
self.failUnlessEqual(sizeof(X), 0)
X._fields_ = [("a", c_int)]
class Y(X):
pass
self.failUnlessEqual(sizeof(Y), sizeof(X))
Y._fields_ = [("b", c_int)]
class Z(X):
pass
self.failUnlessEqual(sizeof(X), sizeof(c_int))
self.failUnlessEqual(sizeof(Y), sizeof(c_int)*2)
self.failUnlessEqual(sizeof(Z), sizeof(c_int))
self.failUnlessEqual(X._fields_, [("a", c_int)])
self.failUnlessEqual(Y._fields_, [("b", c_int)])
self.failUnlessEqual(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.failUnlessEqual((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.failUnlessEqual((sizeof(X), code),
(calcsize("%c" % (code)), code))
def test_struct_alignment(self):
class X(Structure):
_fields_ = [("x", c_char * 3)]
self.failUnlessEqual(alignment(X), calcsize("s"))
self.failUnlessEqual(sizeof(X), calcsize("3s"))
class Y(Structure):
_fields_ = [("x", c_char * 3),
("y", c_int)]
self.failUnlessEqual(alignment(Y), calcsize("i"))
self.failUnlessEqual(sizeof(Y), calcsize("3si"))
class SI(Structure):
_fields_ = [("a", X),
("b", Y)]
self.failUnlessEqual(alignment(SI), max(alignment(Y), alignment(X)))
self.failUnlessEqual(sizeof(SI), calcsize("3s0i 3si 0i"))
class IS(Structure):
_fields_ = [("b", Y),
("a", X)]
self.failUnlessEqual(alignment(SI), max(alignment(X), alignment(Y)))
self.failUnlessEqual(sizeof(IS), calcsize("3si 3s 0i"))
class XX(Structure):
_fields_ = [("a", X),
("b", X)]
self.failUnlessEqual(alignment(XX), alignment(X))
self.failUnlessEqual(sizeof(XX), calcsize("3s 3s 0s"))
def test_emtpy(self):
# I had problems with these
#
# Although these are patological cases: Empty Structures!
class X(Structure):
_fields_ = []
class Y(Union):
_fields_ = []
# Is this really the correct alignment, or should it be 0?
self.failUnless(alignment(X) == alignment(Y) == 1)
self.failUnless(sizeof(X) == sizeof(Y) == 0)
class XX(Structure):
_fields_ = [("a", X),
("b", X)]
self.failUnlessEqual(alignment(XX), 1)
self.failUnlessEqual(sizeof(XX), 0)
def test_fields(self):
# test the offset and size attributes of Structure/Unoin fields.
class X(Structure):
_fields_ = [("x", c_int),
("y", c_char)]
self.failUnlessEqual(X.x.offset, 0)
self.failUnlessEqual(X.x.size, sizeof(c_int))
self.failUnlessEqual(X.y.offset, sizeof(c_int))
self.failUnlessEqual(X.y.size, sizeof(c_char))
# readonly
self.assertRaises(TypeError, setattr, X.x, "offset", 92)
self.assertRaises(TypeError, setattr, X.x, "size", 92)
class X(Union):
_fields_ = [("x", c_int),
("y", c_char)]
self.failUnlessEqual(X.x.offset, 0)
self.failUnlessEqual(X.x.size, sizeof(c_int))
self.failUnlessEqual(X.y.offset, 0)
self.failUnlessEqual(X.y.size, sizeof(c_char))
# readonly
self.assertRaises(TypeError, setattr, X.x, "offset", 92)
self.assertRaises(TypeError, 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.failUnlessEqual(sizeof(X), 9)
self.failUnlessEqual(X.b.offset, 1)
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 2
self.failUnlessEqual(sizeof(X), 10)
self.failUnlessEqual(X.b.offset, 2)
class X(Structure):
_fields_ = [("a", c_byte),
("b", c_longlong)]
_pack_ = 4
self.failUnlessEqual(sizeof(X), 12)
self.failUnlessEqual(X.b.offset, 4)
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_ = 8
self.failUnlessEqual(sizeof(X), longlong_align + longlong_size)
self.failUnlessEqual(X.b.offset, min(8, longlong_align))
d = {"_fields_": [("a", "b"),
("b", "q")],
"_pack_": -1}
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, "asldkjaslkdjaslkdj")
self.assertRaises(TypeError, Person, "Name", "HI")
# short enough
self.failUnlessEqual(Person("12345", 5).name, "12345")
# exact fit
self.failUnlessEqual(Person("123456", 5).name, "123456")
# too long
self.assertRaises(ValueError, Person, "1234567", 5)
def test_keyword_initializers(self):
class POINT(Structure):
_fields_ = [("x", c_int), ("y", c_int)]
pt = POINT(1, 2)
self.failUnlessEqual((pt.x, pt.y), (1, 2))
pt = POINT(y=2, x=1)
self.failUnlessEqual((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_intarray_fields(self):
class SomeInts(Structure):
_fields_ = [("a", c_int * 4)]
# can use tuple to initialize array (but not list!)
self.failUnlessEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0])
self.failUnlessEqual(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("Someone", ("1234", "5678"), 5)
self.failUnlessEqual(p.name, "Someone")
self.failUnlessEqual(p.phone.areacode, "1234")
self.failUnlessEqual(p.phone.number, "5678")
self.failUnlessEqual(p.age, 5)
def test_structures_with_wchar(self):
try:
c_wchar
except NameError:
return # no unicode
class PersonW(Structure):
_fields_ = [("name", c_wchar * 12),
("age", c_int)]
p = PersonW(u"Someone")
self.failUnlessEqual(p.name, "Someone")
self.failUnlessEqual(PersonW(u"1234567890").name, u"1234567890")
self.failUnlessEqual(PersonW(u"12345678901").name, u"12345678901")
# exact fit
self.failUnlessEqual(PersonW(u"123456789012").name, u"123456789012")
#too long
self.assertRaises(ValueError, PersonW, u"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, "Someone", (1, 2))
self.failUnlessEqual(cls, RuntimeError)
# In Python 2.5, Exception is a new-style class, and the repr changed
if issubclass(Exception, object):
self.failUnlessEqual(msg,
"(Phone) <type 'exceptions.TypeError'>: "
"expected string or Unicode object, int found")
else:
self.failUnlessEqual(msg,
"(Phone) TypeError: "
"expected string or Unicode object, int found")
cls, msg = self.get_except(Person, "Someone", ("a", "b", "c"))
self.failUnlessEqual(cls, RuntimeError)
if issubclass(Exception, object):
self.failUnlessEqual(msg,
"(Phone) <type 'exceptions.ValueError'>: too many initializers")
else:
self.failUnlessEqual(msg, "(Phone) ValueError: too many initializers")
def get_except(self, func, *args):
try:
func(*args)
except Exception, detail:
return detail.__class__, str(detail)
## 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.failUnlessEqual((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.failUnlessEqual((cls, msg), (TypeError, "abstract class"))
def test_methods(self):
## class X(Structure):
## _fields_ = []
self.failUnless("in_dll" in dir(type(Structure)))
self.failUnless("from_address" in dir(type(Structure)))
self.failUnless("in_dll" in dir(type(Structure)))
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.failUnlessEqual(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.failUnlessEqual(items, [42, 2, 3])
s.array[0] = 1
## s.array[1] = 42
items = [s.array[i] for i in range(3)]
self.failUnlessEqual(items, [1, 2, 3])
if __name__ == '__main__':
unittest.main()