blob: 976473c46feb5b8ecdf3a997834d087cb21dde42 [file] [log] [blame]
Josh Gaoc62e49a2016-04-29 18:11:04 -07001import 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 Incomplete(Structure):
96 pass
97
98class Complete(Structure):
99 pass
100PComplete = POINTER(Complete)
101Complete._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#
108native_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
177class BEPoint(BigEndianStructure):
178 _fields_ = [("x", c_long), ("y", c_long)]
179
180class 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#
188endian_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
195if __name__ == "__main__":
196 unittest.main()