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