Home | History | Annotate | Download | only in test
      1 import sys, unittest, struct, math, ctypes
      2 from binascii import hexlify
      3 
      4 from ctypes import *
      5 
      6 def bin(s):
      7     return hexlify(memoryview(s)).upper()
      8 
      9 # Each *simple* type that supports different byte orders has an
     10 # __ctype_be__ attribute that specifies the same type in BIG ENDIAN
     11 # byte order, and a __ctype_le__ attribute that is the same type in
     12 # LITTLE ENDIAN byte order.
     13 #
     14 # For Structures and Unions, these types are created on demand.
     15 
     16 class Test(unittest.TestCase):
     17     def X_test(self):
     18         print >> sys.stderr,  sys.byteorder
     19         for i in range(32):
     20             bits = BITS()
     21             setattr(bits, "i%s" % i, 1)
     22             dump(bits)
     23 
     24     def test_endian_short(self):
     25         if sys.byteorder == "little":
     26             self.assertTrue(c_short.__ctype_le__ is c_short)
     27             self.assertTrue(c_short.__ctype_be__.__ctype_le__ is c_short)
     28         else:
     29             self.assertTrue(c_short.__ctype_be__ is c_short)
     30             self.assertTrue(c_short.__ctype_le__.__ctype_be__ is c_short)
     31         s = c_short.__ctype_be__(0x1234)
     32         self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
     33         self.assertEqual(bin(s), "1234")
     34         self.assertEqual(s.value, 0x1234)
     35 
     36         s = c_short.__ctype_le__(0x1234)
     37         self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
     38         self.assertEqual(bin(s), "3412")
     39         self.assertEqual(s.value, 0x1234)
     40 
     41         s = c_ushort.__ctype_be__(0x1234)
     42         self.assertEqual(bin(struct.pack(">h", 0x1234)), "1234")
     43         self.assertEqual(bin(s), "1234")
     44         self.assertEqual(s.value, 0x1234)
     45 
     46         s = c_ushort.__ctype_le__(0x1234)
     47         self.assertEqual(bin(struct.pack("<h", 0x1234)), "3412")
     48         self.assertEqual(bin(s), "3412")
     49         self.assertEqual(s.value, 0x1234)
     50 
     51     def test_endian_int(self):
     52         if sys.byteorder == "little":
     53             self.assertTrue(c_int.__ctype_le__ is c_int)
     54             self.assertTrue(c_int.__ctype_be__.__ctype_le__ is c_int)
     55         else:
     56             self.assertTrue(c_int.__ctype_be__ is c_int)
     57             self.assertTrue(c_int.__ctype_le__.__ctype_be__ is c_int)
     58 
     59         s = c_int.__ctype_be__(0x12345678)
     60         self.assertEqual(bin(struct.pack(">i", 0x12345678)), "12345678")
     61         self.assertEqual(bin(s), "12345678")
     62         self.assertEqual(s.value, 0x12345678)
     63 
     64         s = c_int.__ctype_le__(0x12345678)
     65         self.assertEqual(bin(struct.pack("<i", 0x12345678)), "78563412")
     66         self.assertEqual(bin(s), "78563412")
     67         self.assertEqual(s.value, 0x12345678)
     68 
     69         s = c_uint.__ctype_be__(0x12345678)
     70         self.assertEqual(bin(struct.pack(">I", 0x12345678)), "12345678")
     71         self.assertEqual(bin(s), "12345678")
     72         self.assertEqual(s.value, 0x12345678)
     73 
     74         s = c_uint.__ctype_le__(0x12345678)
     75         self.assertEqual(bin(struct.pack("<I", 0x12345678)), "78563412")
     76         self.assertEqual(bin(s), "78563412")
     77         self.assertEqual(s.value, 0x12345678)
     78 
     79     def test_endian_longlong(self):
     80         if sys.byteorder == "little":
     81             self.assertTrue(c_longlong.__ctype_le__ is c_longlong)
     82             self.assertTrue(c_longlong.__ctype_be__.__ctype_le__ is c_longlong)
     83         else:
     84             self.assertTrue(c_longlong.__ctype_be__ is c_longlong)
     85             self.assertTrue(c_longlong.__ctype_le__.__ctype_be__ is c_longlong)
     86 
     87         s = c_longlong.__ctype_be__(0x1234567890ABCDEF)
     88         self.assertEqual(bin(struct.pack(">q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
     89         self.assertEqual(bin(s), "1234567890ABCDEF")
     90         self.assertEqual(s.value, 0x1234567890ABCDEF)
     91 
     92         s = c_longlong.__ctype_le__(0x1234567890ABCDEF)
     93         self.assertEqual(bin(struct.pack("<q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
     94         self.assertEqual(bin(s), "EFCDAB9078563412")
     95         self.assertEqual(s.value, 0x1234567890ABCDEF)
     96 
     97         s = c_ulonglong.__ctype_be__(0x1234567890ABCDEF)
     98         self.assertEqual(bin(struct.pack(">Q", 0x1234567890ABCDEF)), "1234567890ABCDEF")
     99         self.assertEqual(bin(s), "1234567890ABCDEF")
    100         self.assertEqual(s.value, 0x1234567890ABCDEF)
    101 
    102         s = c_ulonglong.__ctype_le__(0x1234567890ABCDEF)
    103         self.assertEqual(bin(struct.pack("<Q", 0x1234567890ABCDEF)), "EFCDAB9078563412")
    104         self.assertEqual(bin(s), "EFCDAB9078563412")
    105         self.assertEqual(s.value, 0x1234567890ABCDEF)
    106 
    107     def test_endian_float(self):
    108         if sys.byteorder == "little":
    109             self.assertTrue(c_float.__ctype_le__ is c_float)
    110             self.assertTrue(c_float.__ctype_be__.__ctype_le__ is c_float)
    111         else:
    112             self.assertTrue(c_float.__ctype_be__ is c_float)
    113             self.assertTrue(c_float.__ctype_le__.__ctype_be__ is c_float)
    114         s = c_float(math.pi)
    115         self.assertEqual(bin(struct.pack("f", math.pi)), bin(s))
    116         # Hm, what's the precision of a float compared to a double?
    117         self.assertAlmostEqual(s.value, math.pi, 6)
    118         s = c_float.__ctype_le__(math.pi)
    119         self.assertAlmostEqual(s.value, math.pi, 6)
    120         self.assertEqual(bin(struct.pack("<f", math.pi)), bin(s))
    121         s = c_float.__ctype_be__(math.pi)
    122         self.assertAlmostEqual(s.value, math.pi, 6)
    123         self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s))
    124 
    125     def test_endian_double(self):
    126         if sys.byteorder == "little":
    127             self.assertTrue(c_double.__ctype_le__ is c_double)
    128             self.assertTrue(c_double.__ctype_be__.__ctype_le__ is c_double)
    129         else:
    130             self.assertTrue(c_double.__ctype_be__ is c_double)
    131             self.assertTrue(c_double.__ctype_le__.__ctype_be__ is c_double)
    132         s = c_double(math.pi)
    133         self.assertEqual(s.value, math.pi)
    134         self.assertEqual(bin(struct.pack("d", math.pi)), bin(s))
    135         s = c_double.__ctype_le__(math.pi)
    136         self.assertEqual(s.value, math.pi)
    137         self.assertEqual(bin(struct.pack("<d", math.pi)), bin(s))
    138         s = c_double.__ctype_be__(math.pi)
    139         self.assertEqual(s.value, math.pi)
    140         self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))
    141 
    142     def test_endian_other(self):
    143         self.assertTrue(c_byte.__ctype_le__ is c_byte)
    144         self.assertTrue(c_byte.__ctype_be__ is c_byte)
    145 
    146         self.assertTrue(c_ubyte.__ctype_le__ is c_ubyte)
    147         self.assertTrue(c_ubyte.__ctype_be__ is c_ubyte)
    148 
    149         self.assertTrue(c_char.__ctype_le__ is c_char)
    150         self.assertTrue(c_char.__ctype_be__ is c_char)
    151 
    152     def test_struct_fields_1(self):
    153         if sys.byteorder == "little":
    154             base = BigEndianStructure
    155         else:
    156             base = LittleEndianStructure
    157 
    158         class T(base):
    159             pass
    160         _fields_ = [("a", c_ubyte),
    161                     ("b", c_byte),
    162                     ("c", c_short),
    163                     ("d", c_ushort),
    164                     ("e", c_int),
    165                     ("f", c_uint),
    166                     ("g", c_long),
    167                     ("h", c_ulong),
    168                     ("i", c_longlong),
    169                     ("k", c_ulonglong),
    170                     ("l", c_float),
    171                     ("m", c_double),
    172                     ("n", c_char),
    173 
    174                     ("b1", c_byte, 3),
    175                     ("b2", c_byte, 3),
    176                     ("b3", c_byte, 2),
    177                     ("a", c_int * 3 * 3 * 3)]
    178         T._fields_ = _fields_
    179 
    180         # these fields do not support different byte order:
    181         for typ in c_wchar, c_void_p, POINTER(c_int):
    182             _fields_.append(("x", typ))
    183             class T(base):
    184                 pass
    185             self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)])
    186 
    187     def test_struct_struct(self):
    188         # nested structures with different byteorders
    189 
    190         # create nested structures with given byteorders and set memory to data
    191 
    192         for nested, data in (
    193             (BigEndianStructure, b'\0\0\0\1\0\0\0\2'),
    194             (LittleEndianStructure, b'\1\0\0\0\2\0\0\0'),
    195         ):
    196             for parent in (
    197                 BigEndianStructure,
    198                 LittleEndianStructure,
    199                 Structure,
    200             ):
    201                 class NestedStructure(nested):
    202                     _fields_ = [("x", c_uint32),
    203                                 ("y", c_uint32)]
    204 
    205                 class TestStructure(parent):
    206                     _fields_ = [("point", NestedStructure)]
    207 
    208                 self.assertEqual(len(data), sizeof(TestStructure))
    209                 ptr = POINTER(TestStructure)
    210                 s = cast(data, ptr)[0]
    211                 del ctypes._pointer_type_cache[TestStructure]
    212                 self.assertEqual(s.point.x, 1)
    213                 self.assertEqual(s.point.y, 2)
    214 
    215     def test_struct_fields_2(self):
    216         # standard packing in struct uses no alignment.
    217         # So, we have to align using pad bytes.
    218         #
    219         # Unaligned accesses will crash Python (on those platforms that
    220         # don't allow it, like sparc solaris).
    221         if sys.byteorder == "little":
    222             base = BigEndianStructure
    223             fmt = ">bxhid"
    224         else:
    225             base = LittleEndianStructure
    226             fmt = "<bxhid"
    227 
    228         class S(base):
    229             _fields_ = [("b", c_byte),
    230                         ("h", c_short),
    231                         ("i", c_int),
    232                         ("d", c_double)]
    233 
    234         s1 = S(0x12, 0x1234, 0x12345678, 3.14)
    235         s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
    236         self.assertEqual(bin(s1), bin(s2))
    237 
    238     def test_unaligned_nonnative_struct_fields(self):
    239         if sys.byteorder == "little":
    240             base = BigEndianStructure
    241             fmt = ">b h xi xd"
    242         else:
    243             base = LittleEndianStructure
    244             fmt = "<b h xi xd"
    245 
    246         class S(base):
    247             _pack_ = 1
    248             _fields_ = [("b", c_byte),
    249 
    250                         ("h", c_short),
    251 
    252                         ("_1", c_byte),
    253                         ("i", c_int),
    254 
    255                         ("_2", c_byte),
    256                         ("d", c_double)]
    257 
    258         s1 = S()
    259         s1.b = 0x12
    260         s1.h = 0x1234
    261         s1.i = 0x12345678
    262         s1.d = 3.14
    263         s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
    264         self.assertEqual(bin(s1), bin(s2))
    265 
    266     def test_unaligned_native_struct_fields(self):
    267         if sys.byteorder == "little":
    268             fmt = "<b h xi xd"
    269         else:
    270             base = LittleEndianStructure
    271             fmt = ">b h xi xd"
    272 
    273         class S(Structure):
    274             _pack_ = 1
    275             _fields_ = [("b", c_byte),
    276 
    277                         ("h", c_short),
    278 
    279                         ("_1", c_byte),
    280                         ("i", c_int),
    281 
    282                         ("_2", c_byte),
    283                         ("d", c_double)]
    284 
    285         s1 = S()
    286         s1.b = 0x12
    287         s1.h = 0x1234
    288         s1.i = 0x12345678
    289         s1.d = 3.14
    290         s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
    291         self.assertEqual(bin(s1), bin(s2))
    292 
    293 if __name__ == "__main__":
    294     unittest.main()
    295