PageRenderTime 89ms CodeModel.GetById 22ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 1ms

/Lib/ctypes/test/test_structures.py

http://unladen-swallow.googlecode.com/
Python | 449 lines | 320 code | 89 blank | 40 comment | 16 complexity | b03c1518dfcdce9b2a58111ffcd2255b MD5 | raw file
  1import unittest
  2from ctypes import *
  3from struct import calcsize
  4
  5class SubclassesTest(unittest.TestCase):
  6    def test_subclass(self):
  7        class X(Structure):
  8            _fields_ = [("a", c_int)]
  9
 10        class Y(X):
 11            _fields_ = [("b", c_int)]
 12
 13        class Z(X):
 14            pass
 15
 16        self.failUnlessEqual(sizeof(X), sizeof(c_int))
 17        self.failUnlessEqual(sizeof(Y), sizeof(c_int)*2)
 18        self.failUnlessEqual(sizeof(Z), sizeof(c_int))
 19        self.failUnlessEqual(X._fields_, [("a", c_int)])
 20        self.failUnlessEqual(Y._fields_, [("b", c_int)])
 21        self.failUnlessEqual(Z._fields_, [("a", c_int)])
 22
 23    def test_subclass_delayed(self):
 24        class X(Structure):
 25            pass
 26        self.failUnlessEqual(sizeof(X), 0)
 27        X._fields_ = [("a", c_int)]
 28
 29        class Y(X):
 30            pass
 31        self.failUnlessEqual(sizeof(Y), sizeof(X))
 32        Y._fields_ = [("b", c_int)]
 33
 34        class Z(X):
 35            pass
 36
 37        self.failUnlessEqual(sizeof(X), sizeof(c_int))
 38        self.failUnlessEqual(sizeof(Y), sizeof(c_int)*2)
 39        self.failUnlessEqual(sizeof(Z), sizeof(c_int))
 40        self.failUnlessEqual(X._fields_, [("a", c_int)])
 41        self.failUnlessEqual(Y._fields_, [("b", c_int)])
 42        self.failUnlessEqual(Z._fields_, [("a", c_int)])
 43
 44class StructureTestCase(unittest.TestCase):
 45    formats = {"c": c_char,
 46               "b": c_byte,
 47               "B": c_ubyte,
 48               "h": c_short,
 49               "H": c_ushort,
 50               "i": c_int,
 51               "I": c_uint,
 52               "l": c_long,
 53               "L": c_ulong,
 54               "q": c_longlong,
 55               "Q": c_ulonglong,
 56               "f": c_float,
 57               "d": c_double,
 58               }
 59
 60    def test_simple_structs(self):
 61        for code, tp in self.formats.items():
 62            class X(Structure):
 63                _fields_ = [("x", c_char),
 64                            ("y", tp)]
 65            self.failUnlessEqual((sizeof(X), code),
 66                                 (calcsize("c%c0%c" % (code, code)), code))
 67
 68    def test_unions(self):
 69        for code, tp in self.formats.items():
 70            class X(Union):
 71                _fields_ = [("x", c_char),
 72                            ("y", tp)]
 73            self.failUnlessEqual((sizeof(X), code),
 74                                 (calcsize("%c" % (code)), code))
 75
 76    def test_struct_alignment(self):
 77        class X(Structure):
 78            _fields_ = [("x", c_char * 3)]
 79        self.failUnlessEqual(alignment(X), calcsize("s"))
 80        self.failUnlessEqual(sizeof(X), calcsize("3s"))
 81
 82        class Y(Structure):
 83            _fields_ = [("x", c_char * 3),
 84                        ("y", c_int)]
 85        self.failUnlessEqual(alignment(Y), calcsize("i"))
 86        self.failUnlessEqual(sizeof(Y), calcsize("3si"))
 87
 88        class SI(Structure):
 89            _fields_ = [("a", X),
 90                        ("b", Y)]
 91        self.failUnlessEqual(alignment(SI), max(alignment(Y), alignment(X)))
 92        self.failUnlessEqual(sizeof(SI), calcsize("3s0i 3si 0i"))
 93
 94        class IS(Structure):
 95            _fields_ = [("b", Y),
 96                        ("a", X)]
 97
 98        self.failUnlessEqual(alignment(SI), max(alignment(X), alignment(Y)))
 99        self.failUnlessEqual(sizeof(IS), calcsize("3si 3s 0i"))
100
101        class XX(Structure):
102            _fields_ = [("a", X),
103                        ("b", X)]
104        self.failUnlessEqual(alignment(XX), alignment(X))
105        self.failUnlessEqual(sizeof(XX), calcsize("3s 3s 0s"))
106
107    def test_emtpy(self):
108        # I had problems with these
109        #
110        # Although these are patological cases: Empty Structures!
111        class X(Structure):
112            _fields_ = []
113
114        class Y(Union):
115            _fields_ = []
116
117        # Is this really the correct alignment, or should it be 0?
118        self.failUnless(alignment(X) == alignment(Y) == 1)
119        self.failUnless(sizeof(X) == sizeof(Y) == 0)
120
121        class XX(Structure):
122            _fields_ = [("a", X),
123                        ("b", X)]
124
125        self.failUnlessEqual(alignment(XX), 1)
126        self.failUnlessEqual(sizeof(XX), 0)
127
128    def test_fields(self):
129        # test the offset and size attributes of Structure/Unoin fields.
130        class X(Structure):
131            _fields_ = [("x", c_int),
132                        ("y", c_char)]
133
134        self.failUnlessEqual(X.x.offset, 0)
135        self.failUnlessEqual(X.x.size, sizeof(c_int))
136
137        self.failUnlessEqual(X.y.offset, sizeof(c_int))
138        self.failUnlessEqual(X.y.size, sizeof(c_char))
139
140        # readonly
141        self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)
142        self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)
143
144        class X(Union):
145            _fields_ = [("x", c_int),
146                        ("y", c_char)]
147
148        self.failUnlessEqual(X.x.offset, 0)
149        self.failUnlessEqual(X.x.size, sizeof(c_int))
150
151        self.failUnlessEqual(X.y.offset, 0)
152        self.failUnlessEqual(X.y.size, sizeof(c_char))
153
154        # readonly
155        self.assertRaises((TypeError, AttributeError), setattr, X.x, "offset", 92)
156        self.assertRaises((TypeError, AttributeError), setattr, X.x, "size", 92)
157
158        # XXX Should we check nested data types also?
159        # offset is always relative to the class...
160
161    def test_packed(self):
162        class X(Structure):
163            _fields_ = [("a", c_byte),
164                        ("b", c_longlong)]
165            _pack_ = 1
166
167        self.failUnlessEqual(sizeof(X), 9)
168        self.failUnlessEqual(X.b.offset, 1)
169
170        class X(Structure):
171            _fields_ = [("a", c_byte),
172                        ("b", c_longlong)]
173            _pack_ = 2
174        self.failUnlessEqual(sizeof(X), 10)
175        self.failUnlessEqual(X.b.offset, 2)
176
177        class X(Structure):
178            _fields_ = [("a", c_byte),
179                        ("b", c_longlong)]
180            _pack_ = 4
181        self.failUnlessEqual(sizeof(X), 12)
182        self.failUnlessEqual(X.b.offset, 4)
183
184        import struct
185        longlong_size = struct.calcsize("q")
186        longlong_align = struct.calcsize("bq") - longlong_size
187
188        class X(Structure):
189            _fields_ = [("a", c_byte),
190                        ("b", c_longlong)]
191            _pack_ = 8
192
193        self.failUnlessEqual(sizeof(X), longlong_align + longlong_size)
194        self.failUnlessEqual(X.b.offset, min(8, longlong_align))
195
196
197        d = {"_fields_": [("a", "b"),
198                          ("b", "q")],
199             "_pack_": -1}
200        self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
201
202    def test_initializers(self):
203        class Person(Structure):
204            _fields_ = [("name", c_char*6),
205                        ("age", c_int)]
206
207        self.assertRaises(TypeError, Person, 42)
208        self.assertRaises(ValueError, Person, "asldkjaslkdjaslkdj")
209        self.assertRaises(TypeError, Person, "Name", "HI")
210
211        # short enough
212        self.failUnlessEqual(Person("12345", 5).name, "12345")
213        # exact fit
214        self.failUnlessEqual(Person("123456", 5).name, "123456")
215        # too long
216        self.assertRaises(ValueError, Person, "1234567", 5)
217
218    def test_conflicting_initializers(self):
219        class POINT(Structure):
220            _fields_ = [("x", c_int), ("y", c_int)]
221        # conflicting positional and keyword args
222        self.assertRaises(TypeError, POINT, 2, 3, x=4)
223        self.assertRaises(TypeError, POINT, 2, 3, y=4)
224
225        # too many initializers
226        self.assertRaises(TypeError, POINT, 2, 3, 4)
227
228    def test_keyword_initializers(self):
229        class POINT(Structure):
230            _fields_ = [("x", c_int), ("y", c_int)]
231        pt = POINT(1, 2)
232        self.failUnlessEqual((pt.x, pt.y), (1, 2))
233
234        pt = POINT(y=2, x=1)
235        self.failUnlessEqual((pt.x, pt.y), (1, 2))
236
237    def test_invalid_field_types(self):
238        class POINT(Structure):
239            pass
240        self.assertRaises(TypeError, setattr, POINT, "_fields_", [("x", 1), ("y", 2)])
241
242    def test_intarray_fields(self):
243        class SomeInts(Structure):
244            _fields_ = [("a", c_int * 4)]
245
246        # can use tuple to initialize array (but not list!)
247        self.failUnlessEqual(SomeInts((1, 2)).a[:], [1, 2, 0, 0])
248        self.failUnlessEqual(SomeInts((1, 2)).a[::], [1, 2, 0, 0])
249        self.failUnlessEqual(SomeInts((1, 2)).a[::-1], [0, 0, 2, 1])
250        self.failUnlessEqual(SomeInts((1, 2)).a[::2], [1, 0])
251        self.failUnlessEqual(SomeInts((1, 2)).a[1:5:6], [2])
252        self.failUnlessEqual(SomeInts((1, 2)).a[6:4:-1], [])
253        self.failUnlessEqual(SomeInts((1, 2, 3, 4)).a[:], [1, 2, 3, 4])
254        self.failUnlessEqual(SomeInts((1, 2, 3, 4)).a[::], [1, 2, 3, 4])
255        # too long
256        # XXX Should raise ValueError?, not RuntimeError
257        self.assertRaises(RuntimeError, SomeInts, (1, 2, 3, 4, 5))
258
259    def test_nested_initializers(self):
260        # test initializing nested structures
261        class Phone(Structure):
262            _fields_ = [("areacode", c_char*6),
263                        ("number", c_char*12)]
264
265        class Person(Structure):
266            _fields_ = [("name", c_char * 12),
267                        ("phone", Phone),
268                        ("age", c_int)]
269
270        p = Person("Someone", ("1234", "5678"), 5)
271
272        self.failUnlessEqual(p.name, "Someone")
273        self.failUnlessEqual(p.phone.areacode, "1234")
274        self.failUnlessEqual(p.phone.number, "5678")
275        self.failUnlessEqual(p.age, 5)
276
277    def test_structures_with_wchar(self):
278        try:
279            c_wchar
280        except NameError:
281            return # no unicode
282
283        class PersonW(Structure):
284            _fields_ = [("name", c_wchar * 12),
285                        ("age", c_int)]
286
287        p = PersonW(u"Someone")
288        self.failUnlessEqual(p.name, "Someone")
289
290        self.failUnlessEqual(PersonW(u"1234567890").name, u"1234567890")
291        self.failUnlessEqual(PersonW(u"12345678901").name, u"12345678901")
292        # exact fit
293        self.failUnlessEqual(PersonW(u"123456789012").name, u"123456789012")
294        #too long
295        self.assertRaises(ValueError, PersonW, u"1234567890123")
296
297    def test_init_errors(self):
298        class Phone(Structure):
299            _fields_ = [("areacode", c_char*6),
300                        ("number", c_char*12)]
301
302        class Person(Structure):
303            _fields_ = [("name", c_char * 12),
304                        ("phone", Phone),
305                        ("age", c_int)]
306
307        cls, msg = self.get_except(Person, "Someone", (1, 2))
308        self.failUnlessEqual(cls, RuntimeError)
309        # In Python 2.5, Exception is a new-style class, and the repr changed
310        if issubclass(Exception, object):
311            self.failUnlessEqual(msg,
312                                 "(Phone) <type 'exceptions.TypeError'>: "
313                                 "expected string or Unicode object, int found")
314        else:
315            self.failUnlessEqual(msg,
316                                 "(Phone) exceptions.TypeError: "
317                                 "expected string or Unicode object, int found")
318
319        cls, msg = self.get_except(Person, "Someone", ("a", "b", "c"))
320        self.failUnlessEqual(cls, RuntimeError)
321        if issubclass(Exception, object):
322            self.failUnlessEqual(msg,
323                                 "(Phone) <type 'exceptions.TypeError'>: too many initializers")
324        else:
325            self.failUnlessEqual(msg, "(Phone) exceptions.TypeError: too many initializers")
326
327
328    def get_except(self, func, *args):
329        try:
330            func(*args)
331        except Exception, detail:
332            return detail.__class__, str(detail)
333
334
335##    def test_subclass_creation(self):
336##        meta = type(Structure)
337##        # same as 'class X(Structure): pass'
338##        # fails, since we need either a _fields_ or a _abstract_ attribute
339##        cls, msg = self.get_except(meta, "X", (Structure,), {})
340##        self.failUnlessEqual((cls, msg),
341##                             (AttributeError, "class must define a '_fields_' attribute"))
342
343    def test_abstract_class(self):
344        class X(Structure):
345            _abstract_ = "something"
346        # try 'X()'
347        cls, msg = self.get_except(eval, "X()", locals())
348        self.failUnlessEqual((cls, msg), (TypeError, "abstract class"))
349
350    def test_methods(self):
351##        class X(Structure):
352##            _fields_ = []
353
354        self.failUnless("in_dll" in dir(type(Structure)))
355        self.failUnless("from_address" in dir(type(Structure)))
356        self.failUnless("in_dll" in dir(type(Structure)))
357
358    def test_positional_args(self):
359        # see also http://bugs.python.org/issue5042
360        class W(Structure):
361            _fields_ = [("a", c_int), ("b", c_int)]
362        class X(W):
363            _fields_ = [("c", c_int)]
364        class Y(X):
365            pass
366        class Z(Y):
367            _fields_ = [("d", c_int), ("e", c_int), ("f", c_int)]
368
369        z = Z(1, 2, 3, 4, 5, 6)
370        self.failUnlessEqual((z.a, z.b, z.c, z.d, z.e, z.f),
371                             (1, 2, 3, 4, 5, 6))
372        z = Z(1)
373        self.failUnlessEqual((z.a, z.b, z.c, z.d, z.e, z.f),
374                             (1, 0, 0, 0, 0, 0))
375        self.assertRaises(TypeError, lambda: Z(1, 2, 3, 4, 5, 6, 7))
376
377class PointerMemberTestCase(unittest.TestCase):
378
379    def test(self):
380        # a Structure with a POINTER field
381        class S(Structure):
382            _fields_ = [("array", POINTER(c_int))]
383
384        s = S()
385        # We can assign arrays of the correct type
386        s.array = (c_int * 3)(1, 2, 3)
387        items = [s.array[i] for i in range(3)]
388        self.failUnlessEqual(items, [1, 2, 3])
389
390        # The following are bugs, but are included here because the unittests
391        # also describe the current behaviour.
392        #
393        # This fails with SystemError: bad arg to internal function
394        # or with IndexError (with a patch I have)
395
396        s.array[0] = 42
397
398        items = [s.array[i] for i in range(3)]
399        self.failUnlessEqual(items, [42, 2, 3])
400
401        s.array[0] = 1
402
403##        s.array[1] = 42
404
405        items = [s.array[i] for i in range(3)]
406        self.failUnlessEqual(items, [1, 2, 3])
407
408    def test_none_to_pointer_fields(self):
409        class S(Structure):
410            _fields_ = [("x", c_int),
411                        ("p", POINTER(c_int))]
412
413        s = S()
414        s.x = 12345678
415        s.p = None
416        self.failUnlessEqual(s.x, 12345678)
417
418class TestRecursiveStructure(unittest.TestCase):
419    def test_contains_itself(self):
420        class Recursive(Structure):
421            pass
422
423        try:
424            Recursive._fields_ = [("next", Recursive)]
425        except AttributeError, details:
426            self.failUnless("Structure or union cannot contain itself" in
427                            str(details))
428        else:
429            self.fail("Structure or union cannot contain itself")
430
431
432    def test_vice_versa(self):
433        class First(Structure):
434            pass
435        class Second(Structure):
436            pass
437
438        First._fields_ = [("second", Second)]
439
440        try:
441            Second._fields_ = [("first", First)]
442        except AttributeError, details:
443            self.failUnless("_fields_ is final" in
444                            str(details))
445        else:
446            self.fail("AttributeError not raised")
447
448if __name__ == '__main__':
449    unittest.main()