• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
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                # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
35                #     if requested. memoryview currently reconstructs missing
36                #     stride information, so this assert will fail.
37                # self.assertEqual(v.strides, ())
38
39                # they are always read/write
40                self.assertFalse(v.readonly)
41
42                if v.shape:
43                    n = 1
44                    for dim in v.shape:
45                        n = n * dim
46                    self.assertEqual(n * v.itemsize, len(v.tobytes()))
47            except:
48                # so that we can see the failing type
49                print(tp)
50                raise
51
52    def test_endian_types(self):
53        for tp, fmt, shape, itemtp in endian_types:
54            ob = tp()
55            v = memoryview(ob)
56            try:
57                self.assertEqual(v.format, fmt)
58                if shape:
59                    self.assertEqual(len(v), shape[0])
60                else:
61                    self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
62                self.assertEqual(v.itemsize, sizeof(itemtp))
63                self.assertEqual(v.shape, shape)
64                # XXX Issue #12851
65                # self.assertEqual(v.strides, ())
66
67                # they are always read/write
68                self.assertFalse(v.readonly)
69
70                if v.shape:
71                    n = 1
72                    for dim in v.shape:
73                        n = n * dim
74                    self.assertEqual(n, len(v))
75            except:
76                # so that we can see the failing type
77                print(tp)
78                raise
79
80# define some structure classes
81
82class Point(Structure):
83    _fields_ = [("x", c_long), ("y", c_long)]
84
85class PackedPoint(Structure):
86    _pack_ = 2
87    _fields_ = [("x", c_long), ("y", c_long)]
88
89class Point2(Structure):
90    pass
91Point2._fields_ = [("x", c_long), ("y", c_long)]
92
93class EmptyStruct(Structure):
94    _fields_ = []
95
96class aUnion(Union):
97    _fields_ = [("a", c_int)]
98
99class StructWithArrays(Structure):
100    _fields_ = [("x", c_long * 3 * 2), ("y", Point * 4)]
101
102class Incomplete(Structure):
103    pass
104
105class Complete(Structure):
106    pass
107PComplete = POINTER(Complete)
108Complete._fields_ = [("a", c_long)]
109
110################################################################
111#
112# This table contains format strings as they look on little endian
113# machines.  The test replaces '<' with '>' on big endian machines.
114#
115
116# Platform-specific type codes
117s_bool = {1: '?', 2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_bool)]
118s_short = {2: 'h', 4: 'l', 8: 'q'}[sizeof(c_short)]
119s_ushort = {2: 'H', 4: 'L', 8: 'Q'}[sizeof(c_ushort)]
120s_int = {2: 'h', 4: 'i', 8: 'q'}[sizeof(c_int)]
121s_uint = {2: 'H', 4: 'I', 8: 'Q'}[sizeof(c_uint)]
122s_long = {4: 'l', 8: 'q'}[sizeof(c_long)]
123s_ulong = {4: 'L', 8: 'Q'}[sizeof(c_ulong)]
124s_longlong = "q"
125s_ulonglong = "Q"
126s_float = "f"
127s_double = "d"
128s_longdouble = "g"
129
130# Alias definitions in ctypes/__init__.py
131if c_int is c_long:
132    s_int = s_long
133if c_uint is c_ulong:
134    s_uint = s_ulong
135if c_longlong is c_long:
136    s_longlong = s_long
137if c_ulonglong is c_ulong:
138    s_ulonglong = s_ulong
139if c_longdouble is c_double:
140    s_longdouble = s_double
141
142
143native_types = [
144    # type                      format                  shape           calc itemsize
145
146    ## simple types
147
148    (c_char,                    "<c",                   (),           c_char),
149    (c_byte,                    "<b",                   (),           c_byte),
150    (c_ubyte,                   "<B",                   (),           c_ubyte),
151    (c_short,                   "<" + s_short,          (),           c_short),
152    (c_ushort,                  "<" + s_ushort,         (),           c_ushort),
153
154    (c_int,                     "<" + s_int,            (),           c_int),
155    (c_uint,                    "<" + s_uint,           (),           c_uint),
156
157    (c_long,                    "<" + s_long,           (),           c_long),
158    (c_ulong,                   "<" + s_ulong,          (),           c_ulong),
159
160    (c_longlong,                "<" + s_longlong,       (),           c_longlong),
161    (c_ulonglong,               "<" + s_ulonglong,      (),           c_ulonglong),
162
163    (c_float,                   "<f",                   (),           c_float),
164    (c_double,                  "<d",                   (),           c_double),
165
166    (c_longdouble,              "<" + s_longdouble,     (),           c_longdouble),
167
168    (c_bool,                    "<" + s_bool,           (),           c_bool),
169    (py_object,                 "<O",                   (),           py_object),
170
171    ## pointers
172
173    (POINTER(c_byte),           "&<b",                  (),           POINTER(c_byte)),
174    (POINTER(POINTER(c_long)),  "&&<" + s_long,         (),           POINTER(POINTER(c_long))),
175
176    ## arrays and pointers
177
178    (c_double * 4,              "<d",                   (4,),           c_double),
179    (c_float * 4 * 3 * 2,       "<f",                   (2,3,4),        c_float),
180    (POINTER(c_short) * 2,      "&<" + s_short,         (2,),           POINTER(c_short)),
181    (POINTER(c_short) * 2 * 3,  "&<" + s_short,         (3,2,),         POINTER(c_short)),
182    (POINTER(c_short * 2),      "&(2)<" + s_short,      (),             POINTER(c_short)),
183
184    ## structures and unions
185
186    (Point,                     "T{<l:x:<l:y:}".replace('l', s_long),  (),  Point),
187    # packed structures do not implement the pep
188    (PackedPoint,               "B",                                   (),  PackedPoint),
189    (Point2,                    "T{<l:x:<l:y:}".replace('l', s_long),  (),  Point2),
190    (EmptyStruct,               "T{}",                                 (),  EmptyStruct),
191    # the pep doesn't support unions
192    (aUnion,                    "B",                                   (),  aUnion),
193    # structure with sub-arrays
194    (StructWithArrays, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (), StructWithArrays),
195    (StructWithArrays * 3, "T{(2,3)<l:x:(4)T{<l:x:<l:y:}:y:}".replace('l', s_long), (3,), StructWithArrays),
196
197    ## pointer to incomplete structure
198    (Incomplete,                "B",                    (),           Incomplete),
199    (POINTER(Incomplete),       "&B",                   (),           POINTER(Incomplete)),
200
201    # 'Complete' is a structure that starts incomplete, but is completed after the
202    # pointer type to it has been created.
203    (Complete,                  "T{<l:a:}".replace('l', s_long), (), Complete),
204    # Unfortunately the pointer format string is not fixed...
205    (POINTER(Complete),         "&B",                   (),           POINTER(Complete)),
206
207    ## other
208
209    # function signatures are not implemented
210    (CFUNCTYPE(None),           "X{}",                  (),           CFUNCTYPE(None)),
211
212    ]
213
214class BEPoint(BigEndianStructure):
215    _fields_ = [("x", c_long), ("y", c_long)]
216
217class LEPoint(LittleEndianStructure):
218    _fields_ = [("x", c_long), ("y", c_long)]
219
220################################################################
221#
222# This table contains format strings as they really look, on both big
223# and little endian machines.
224#
225endian_types = [
226    (BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
227    (LEPoint, "T{<l:x:<l:y:}".replace('l', s_long), (), LEPoint),
228    (POINTER(BEPoint), "&T{>l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)),
229    (POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)),
230    ]
231
232if __name__ == "__main__":
233    unittest.main()
234