1import unittest 2from ctypes import * 3import re, sys 4 5if sys.byteorder == "little": 6 THIS_ENDIAN = "<" 7 OTHER_ENDIAN = ">" 8else: 9 THIS_ENDIAN = ">" 10 OTHER_ENDIAN = "<" 11 12def 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 20class 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 78class Point(Structure): 79 _fields_ = [("x", c_long), ("y", c_long)] 80 81class PackedPoint(Structure): 82 _pack_ = 2 83 _fields_ = [("x", c_long), ("y", c_long)] 84 85class Point2(Structure): 86 pass 87Point2._fields_ = [("x", c_long), ("y", c_long)] 88 89class EmptyStruct(Structure): 90 _fields_ = [] 91 92class aUnion(Union): 93 _fields_ = [("a", c_int)] 94 95class StructWithArrays(Structure): 96 _fields_ = [("x", c_long * 3 * 2), ("y", Point * 4)] 97 98 99class Incomplete(Structure): 100 pass 101 102class Complete(Structure): 103 pass 104PComplete = POINTER(Complete) 105Complete._fields_ = [("a", c_long)] 106 107################################################################ 108# 109# This table contains format strings as they look on little endian 110# machines. The test replaces '<' with '>' on big endian machines. 111# 112native_types = [ 113 # type format shape calc itemsize 114 115 ## simple types 116 117 (c_char, "<c", None, c_char), 118 (c_byte, "<b", None, c_byte), 119 (c_ubyte, "<B", None, c_ubyte), 120 (c_short, "<h", None, c_short), 121 (c_ushort, "<H", None, c_ushort), 122 123 # c_int and c_uint may be aliases to c_long 124 #(c_int, "<i", None, c_int), 125 #(c_uint, "<I", None, c_uint), 126 127 (c_long, "<l", None, c_long), 128 (c_ulong, "<L", None, c_ulong), 129 130 # c_longlong and c_ulonglong are aliases on 64-bit platforms 131 #(c_longlong, "<q", None, c_longlong), 132 #(c_ulonglong, "<Q", None, c_ulonglong), 133 134 (c_float, "<f", None, c_float), 135 (c_double, "<d", None, c_double), 136 # c_longdouble may be an alias to c_double 137 138 (c_bool, "<?", None, c_bool), 139 (py_object, "<O", None, py_object), 140 141 ## pointers 142 143 (POINTER(c_byte), "&<b", None, POINTER(c_byte)), 144 (POINTER(POINTER(c_long)), "&&<l", None, POINTER(POINTER(c_long))), 145 146 ## arrays and pointers 147 148 (c_double * 4, "<d", (4,), c_double), 149 (c_float * 4 * 3 * 2, "<f", (2,3,4), c_float), 150 (POINTER(c_short) * 2, "&<h", (2,), POINTER(c_short)), 151 (POINTER(c_short) * 2 * 3, "&<h", (3,2,), POINTER(c_short)), 152 (POINTER(c_short * 2), "&(2)<h", None, POINTER(c_short)), 153 154 ## structures and unions 155 156 (Point, "T{<l:x:<l:y:}", None, Point), 157 # packed structures do not implement the pep 158 (PackedPoint, "B", None, PackedPoint), 159 (Point2, "T{<l:x:<l:y:}", None, Point2), 160 (EmptyStruct, "T{}", None, EmptyStruct), 161 # the pep does't support unions 162 (aUnion, "B", None, aUnion), 163 # structure with sub-arrays 164 (StructWithArrays, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}", None, StructWithArrays), 165 (StructWithArrays * 3, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}", (3,), StructWithArrays), 166 167 ## pointer to incomplete structure 168 (Incomplete, "B", None, Incomplete), 169 (POINTER(Incomplete), "&B", None, POINTER(Incomplete)), 170 171 # 'Complete' is a structure that starts incomplete, but is completed after the 172 # pointer type to it has been created. 173 (Complete, "T{<l:a:}", None, Complete), 174 # Unfortunately the pointer format string is not fixed... 175 (POINTER(Complete), "&B", None, POINTER(Complete)), 176 177 ## other 178 179 # function signatures are not implemented 180 (CFUNCTYPE(None), "X{}", None, CFUNCTYPE(None)), 181 182 ] 183 184class BEPoint(BigEndianStructure): 185 _fields_ = [("x", c_long), ("y", c_long)] 186 187class LEPoint(LittleEndianStructure): 188 _fields_ = [("x", c_long), ("y", c_long)] 189 190################################################################ 191# 192# This table contains format strings as they really look, on both big 193# and little endian machines. 194# 195endian_types = [ 196 (BEPoint, "T{>l:x:>l:y:}", None, BEPoint), 197 (LEPoint, "T{<l:x:<l:y:}", None, LEPoint), 198 (POINTER(BEPoint), "&T{>l:x:>l:y:}", None, POINTER(BEPoint)), 199 (POINTER(LEPoint), "&T{<l:x:<l:y:}", None, POINTER(LEPoint)), 200 ] 201 202if __name__ == "__main__": 203 unittest.main() 204