Home | History | Annotate | Download | only in test
      1 import unittest
      2 from ctypes import *
      3 import re, sys
      4 
      5 if sys.byteorder == "little":
      6     THIS_ENDIAN = "<"
      7     OTHER_ENDIAN = ">"
      8 else:
      9     THIS_ENDIAN = ">"
     10     OTHER_ENDIAN = "<"
     11 
     12 def normalize(format):
     13     # Remove current endian specifier and white space from a format
     14     # string
     15     if format is None:
     16         return ""
     17     format = format.replace(OTHER_ENDIAN, THIS_ENDIAN)
     18     return re.sub(r"\s", "", format)
     19 
     20 class Test(unittest.TestCase):
     21 
     22     def test_native_types(self):
     23         for tp, fmt, shape, itemtp in native_types:
     24             ob = tp()
     25             v = memoryview(ob)
     26             try:
     27                 self.assertEqual(normalize(v.format), normalize(fmt))
     28                 if shape is not None:
     29                     self.assertEqual(len(v), shape[0])
     30                 else:
     31                     self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
     32                 self.assertEqual(v.itemsize, sizeof(itemtp))
     33                 self.assertEqual(v.shape, shape)
     34                 # ctypes object always have a non-strided memory block
     35                 self.assertEqual(v.strides, None)
     36                 # they are always read/write
     37                 self.assertFalse(v.readonly)
     38 
     39                 if v.shape:
     40                     n = 1
     41                     for dim in v.shape:
     42                         n = n * dim
     43                     self.assertEqual(n * v.itemsize, len(v.tobytes()))
     44             except:
     45                 # so that we can see the failing type
     46                 print(tp)
     47                 raise
     48 
     49     def test_endian_types(self):
     50         for tp, fmt, shape, itemtp in endian_types:
     51             ob = tp()
     52             v = memoryview(ob)
     53             try:
     54                 self.assertEqual(v.format, fmt)
     55                 if shape is not None:
     56                     self.assertEqual(len(v), shape[0])
     57                 else:
     58                     self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
     59                 self.assertEqual(v.itemsize, sizeof(itemtp))
     60                 self.assertEqual(v.shape, shape)
     61                 # ctypes object always have a non-strided memory block
     62                 self.assertEqual(v.strides, None)
     63                 # they are always read/write
     64                 self.assertFalse(v.readonly)
     65 
     66                 if v.shape:
     67                     n = 1
     68                     for dim in v.shape:
     69                         n = n * dim
     70                     self.assertEqual(n, len(v))
     71             except:
     72                 # so that we can see the failing type
     73                 print(tp)
     74                 raise
     75 
     76 # define some structure classes
     77 
     78 class Point(Structure):
     79     _fields_ = [("x", c_long), ("y", c_long)]
     80 
     81 class PackedPoint(Structure):
     82     _pack_ = 2
     83     _fields_ = [("x", c_long), ("y", c_long)]
     84 
     85 class Point2(Structure):
     86     pass
     87 Point2._fields_ = [("x", c_long), ("y", c_long)]
     88 
     89 class EmptyStruct(Structure):
     90     _fields_ = []
     91 
     92 class aUnion(Union):
     93     _fields_ = [("a", c_int)]
     94 
     95 class Incomplete(Structure):
     96     pass
     97 
     98 class Complete(Structure):
     99     pass
    100 PComplete = POINTER(Complete)
    101 Complete._fields_ = [("a", c_long)]
    102 
    103 ################################################################
    104 #
    105 # This table contains format strings as they look on little endian
    106 # machines.  The test replaces '<' with '>' on big endian machines.
    107 #
    108 native_types = [
    109     # type                      format                  shape           calc itemsize
    110 
    111     ## simple types
    112 
    113     (c_char,                    "<c",                   None,           c_char),
    114     (c_byte,                    "<b",                   None,           c_byte),
    115     (c_ubyte,                   "<B",                   None,           c_ubyte),
    116     (c_short,                   "<h",                   None,           c_short),
    117     (c_ushort,                  "<H",                   None,           c_ushort),
    118 
    119     # c_int and c_uint may be aliases to c_long
    120     #(c_int,                     "<i",                   None,           c_int),
    121     #(c_uint,                    "<I",                   None,           c_uint),
    122 
    123     (c_long,                    "<l",                   None,           c_long),
    124     (c_ulong,                   "<L",                   None,           c_ulong),
    125 
    126     # c_longlong and c_ulonglong are aliases on 64-bit platforms
    127     #(c_longlong,                "<q",                   None,           c_longlong),
    128     #(c_ulonglong,               "<Q",                   None,           c_ulonglong),
    129 
    130     (c_float,                   "<f",                   None,           c_float),
    131     (c_double,                  "<d",                   None,           c_double),
    132     # c_longdouble may be an alias to c_double
    133 
    134     (c_bool,                    "<?",                   None,           c_bool),
    135     (py_object,                 "<O",                   None,           py_object),
    136 
    137     ## pointers
    138 
    139     (POINTER(c_byte),           "&<b",                  None,           POINTER(c_byte)),
    140     (POINTER(POINTER(c_long)),  "&&<l",                 None,           POINTER(POINTER(c_long))),
    141 
    142     ## arrays and pointers
    143 
    144     (c_double * 4,              "(4)<d",                (4,),           c_double),
    145     (c_float * 4 * 3 * 2,       "(2,3,4)<f",            (2,3,4),        c_float),
    146     (POINTER(c_short) * 2,      "(2)&<h",               (2,),           POINTER(c_short)),
    147     (POINTER(c_short) * 2 * 3,  "(3,2)&<h",             (3,2,),         POINTER(c_short)),
    148     (POINTER(c_short * 2),      "&(2)<h",               None,           POINTER(c_short)),
    149 
    150     ## structures and unions
    151 
    152     (Point,                     "T{<l:x:<l:y:}",        None,           Point),
    153     # packed structures do not implement the pep
    154     (PackedPoint,               "B",                    None,           PackedPoint),
    155     (Point2,                    "T{<l:x:<l:y:}",        None,           Point2),
    156     (EmptyStruct,               "T{}",                  None,           EmptyStruct),
    157     # the pep does't support unions
    158     (aUnion,                    "B",                    None,           aUnion),
    159 
    160     ## pointer to incomplete structure
    161     (Incomplete,                "B",                    None,           Incomplete),
    162     (POINTER(Incomplete),       "&B",                   None,           POINTER(Incomplete)),
    163 
    164     # 'Complete' is a structure that starts incomplete, but is completed after the
    165     # pointer type to it has been created.
    166     (Complete,                  "T{<l:a:}",             None,           Complete),
    167     # Unfortunately the pointer format string is not fixed...
    168     (POINTER(Complete),         "&B",                   None,           POINTER(Complete)),
    169 
    170     ## other
    171 
    172     # function signatures are not implemented
    173     (CFUNCTYPE(None),           "X{}",                  None,           CFUNCTYPE(None)),
    174 
    175     ]
    176 
    177 class BEPoint(BigEndianStructure):
    178     _fields_ = [("x", c_long), ("y", c_long)]
    179 
    180 class LEPoint(LittleEndianStructure):
    181     _fields_ = [("x", c_long), ("y", c_long)]
    182 
    183 ################################################################
    184 #
    185 # This table contains format strings as they really look, on both big
    186 # and little endian machines.
    187 #
    188 endian_types = [
    189     (BEPoint,                   "T{>l:x:>l:y:}",        None,           BEPoint),
    190     (LEPoint,                   "T{<l:x:<l:y:}",        None,           LEPoint),
    191     (POINTER(BEPoint),          "&T{>l:x:>l:y:}",       None,           POINTER(BEPoint)),
    192     (POINTER(LEPoint),          "&T{<l:x:<l:y:}",       None,           POINTER(LEPoint)),
    193     ]
    194 
    195 if __name__ == "__main__":
    196     unittest.main()
    197