blob: 982047a37dc79cdfe3485c5b26e39a88070a5855 [file] [log] [blame]
Thomas Wouters477c8d52006-05-27 19:21:47 +00001import array
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00002import unittest
3import struct
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00004import warnings
Barry Warsaw07a0eec1996-12-12 23:34:06 +00005
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00006from functools import wraps
Brett Cannon1cd02472008-09-09 01:52:27 +00007from test.support import TestFailed, verbose, run_unittest
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +000011IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000012del sys
Tim Peters17e17d42001-06-13 22:45:27 +000013
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000014try:
15 import _struct
16except ImportError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000017 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000018else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000020
Tim Peters17e17d42001-06-13 22:45:27 +000021def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000022 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000023
24def bigendian_to_native(value):
25 if ISBIGENDIAN:
26 return value
27 else:
28 return string_reverse(value)
29
Thomas Wouters0e3f5912006-08-11 14:57:12 +000030def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000031 @wraps(func)
32 def decorator(*args, **kw):
Brett Cannon1cd02472008-09-09 01:52:27 +000033 with warnings.catch_warnings():
Nick Coghlanb1304932008-07-13 12:25:08 +000034 # We need this function to warn every time, so stick an
35 # unqualifed 'always' at the head of the filter list
36 warnings.simplefilter("always")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000037 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000038 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000040
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000041class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000042
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 @with_warning_restore
44 def check_float_coerce(self, format, number):
45 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
46 if PY_STRUCT_FLOAT_COERCE == 2:
47 # Test for pre-2.5 struct module
48 packed = struct.pack(format, number)
49 floored = struct.unpack(format, packed)[0]
50 self.assertEqual(floored, int(number),
51 "did not correcly coerce float to int")
52 return
53 try:
54 struct.pack(format, number)
55 except (struct.error, TypeError):
56 if PY_STRUCT_FLOAT_COERCE:
57 self.fail("expected DeprecationWarning for float coerce")
58 except DeprecationWarning:
59 if not PY_STRUCT_FLOAT_COERCE:
60 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000061 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000063
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000064 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000065 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000066
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000067 def test_consistence(self):
68 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000069
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000070 sz = struct.calcsize('i')
71 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000072
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000073 fmt = 'cbxxxxxxhhhhiillffd?'
74 fmt3 = '3c3b18x12h6i6l6f3d3?'
75 sz = struct.calcsize(fmt)
76 sz3 = struct.calcsize(fmt3)
77 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000078
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000079 self.assertRaises(struct.error, struct.pack, 'iii', 3)
80 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
81 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
82 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
83 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
84 s = struct.pack('ii', 1, 2)
85 self.assertRaises(struct.error, struct.unpack, 'iii', s)
86 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000088 def test_transitiveness(self):
89 c = b'a'
90 b = 1
91 h = 255
92 i = 65535
93 l = 65536
94 f = 3.1415
95 d = 3.1415
96 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000097
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000098 for prefix in ('', '@', '<', '>', '=', '!'):
99 for format in ('xcbhilfd?', 'xcBHILfd?'):
100 format = prefix + format
101 s = struct.pack(format, c, b, h, i, l, f, d, t)
102 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
103 self.assertEqual(cp, c)
104 self.assertEqual(bp, b)
105 self.assertEqual(hp, h)
106 self.assertEqual(ip, i)
107 self.assertEqual(lp, l)
108 self.assertEqual(int(100 * fp), int(100 * f))
109 self.assertEqual(int(100 * dp), int(100 * d))
110 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000111
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000112 def test_new_features(self):
113 # Test some of the new features in detail
114 # (format, argument, big-endian result, little-endian result, asymmetric)
115 tests = [
116 ('c', 'a', 'a', 'a', 0),
117 ('xc', 'a', '\0a', '\0a', 0),
118 ('cx', 'a', 'a\0', 'a\0', 0),
119 ('s', 'a', 'a', 'a', 0),
120 ('0s', 'helloworld', '', '', 1),
121 ('1s', 'helloworld', 'h', 'h', 1),
122 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
123 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
124 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
125 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
126 ('b', 7, '\7', '\7', 0),
127 ('b', -7, '\371', '\371', 0),
128 ('B', 7, '\7', '\7', 0),
129 ('B', 249, '\371', '\371', 0),
130 ('h', 700, '\002\274', '\274\002', 0),
131 ('h', -700, '\375D', 'D\375', 0),
132 ('H', 700, '\002\274', '\274\002', 0),
133 ('H', 0x10000-700, '\375D', 'D\375', 0),
134 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
135 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
136 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
137 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
138 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
139 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
140 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
141 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
142 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
143 ('d', 2.0, '@\000\000\000\000\000\000\000',
144 '\000\000\000\000\000\000\000@', 0),
145 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
146 ('d', -2.0, '\300\000\000\000\000\000\000\000',
147 '\000\000\000\000\000\000\000\300', 0),
148 ('?', 0, '\0', '\0', 0),
149 ('?', 3, '\1', '\1', 1),
150 ('?', True, '\1', '\1', 0),
151 ('?', [], '\0', '\0', 1),
152 ('?', (1,), '\1', '\1', 1),
153 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000154
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000155 for fmt, arg, big, lil, asy in tests:
156 big = bytes(big, "latin-1")
157 lil = bytes(lil, "latin-1")
158 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
159 ('='+fmt, ISBIGENDIAN and big or lil)]:
160 res = struct.pack(xfmt, arg)
161 self.assertEqual(res, exp)
162 self.assertEqual(struct.calcsize(xfmt), len(res))
163 rev = struct.unpack(xfmt, res)[0]
164 if isinstance(arg, str):
165 # Strings are returned as bytes since you can't know the
166 # encoding of the string when packed.
167 arg = bytes(arg, 'latin1')
168 if rev != arg:
169 self.assert_(asy)
170
171 def test_native_qQ(self):
172 # can't pack -1 as unsigned regardless
Mark Dickinson21776072009-02-10 16:13:25 +0000173 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000174 # can't pack string as 'q' regardless
175 self.assertRaises(struct.error, struct.pack, "q", "a")
176 # ditto, but 'Q'
177 self.assertRaises(struct.error, struct.pack, "Q", "a")
178
179 try:
180 struct.pack("q", 5)
181 except struct.error:
182 # does not have native q/Q
183 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000184 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000185 nbytes = struct.calcsize('q')
186 # The expected values here are in big-endian format, primarily
187 # because I'm on a little-endian machine and so this is the
188 # clearest way (for me) to force the code to get exercised.
189 for format, input, expected in (
190 ('q', -1, '\xff' * nbytes),
191 ('q', 0, '\x00' * nbytes),
192 ('Q', 0, '\x00' * nbytes),
193 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
194 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
195 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
196 expected = bytes(expected, "latin-1")
197 got = struct.pack(format, input)
198 native_expected = bigendian_to_native(expected)
199 self.assertEqual(got, native_expected)
200 retrieved = struct.unpack(format, got)[0]
201 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000202
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000203 def test_standard_integers(self):
204 # Standard integer tests (bBhHiIlLqQ).
205 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000206
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000207 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000208
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000209 def __init__(self, formatpair, bytesize):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000210 super(IntTester, self).__init__(methodName='test_one')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000211 self.assertEqual(len(formatpair), 2)
212 self.formatpair = formatpair
213 for direction in "<>!=":
214 for code in formatpair:
215 format = direction + code
216 self.assertEqual(struct.calcsize(format), bytesize)
217 self.bytesize = bytesize
218 self.bitsize = bytesize * 8
219 self.signed_code, self.unsigned_code = formatpair
220 self.unsigned_min = 0
221 self.unsigned_max = 2**self.bitsize - 1
222 self.signed_min = -(2**(self.bitsize-1))
223 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000224
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000225 def test_one(self, x, pack=struct.pack,
226 unpack=struct.unpack,
227 unhexlify=binascii.unhexlify):
228 # Try signed.
229 code = self.signed_code
230 if self.signed_min <= x <= self.signed_max:
231 # Try big-endian.
232 expected = x
233 if x < 0:
234 expected += 1 << self.bitsize
235 self.assert_(expected > 0)
236 expected = hex(expected)[2:] # chop "0x"
237 if len(expected) & 1:
238 expected = "0" + expected
239 expected = unhexlify(expected)
240 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000241
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000242 # Pack work?
243 format = ">" + code
244 got = pack(format, x)
245 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000246
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000247 # Unpack work?
248 retrieved = unpack(format, got)[0]
249 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000250
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000251 # Adding any byte should cause a "too big" error.
252 self.assertRaises((struct.error, TypeError),
253 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000254
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000255 # Try little-endian.
256 format = "<" + code
257 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000258
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000259 # Pack work?
260 got = pack(format, x)
261 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000262
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000263 # Unpack work?
264 retrieved = unpack(format, got)[0]
265 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000266
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000267 # Adding any byte should cause a "too big" error.
268 self.assertRaises((struct.error, TypeError),
269 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000270
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000271 else:
272 # x is out of range -- verify pack realizes that.
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000273 self.assertRaises((struct.error, OverflowError),
274 pack, ">" + code, x)
275 self.assertRaises((struct.error, OverflowError),
276 pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000277
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000278 # Much the same for unsigned.
279 code = self.unsigned_code
280 if self.unsigned_min <= x <= self.unsigned_max:
281 # Try big-endian.
282 format = ">" + code
283 expected = x
284 expected = hex(expected)[2:] # chop "0x"
285 if len(expected) & 1:
286 expected = "0" + expected
287 expected = unhexlify(expected)
288 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000289
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000290 # Pack work?
291 got = pack(format, x)
292 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000293
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000294 # Unpack work?
295 retrieved = unpack(format, got)[0]
296 self.assertEqual(x, retrieved)
297
298 # Adding any byte should cause a "too big" error.
299 self.assertRaises((struct.error, TypeError),
300 unpack, format, b'\x01' + got)
301
302 # Try little-endian.
303 format = "<" + code
304 expected = string_reverse(expected)
305
306 # Pack work?
307 got = pack(format, x)
308 self.assertEqual(got, expected)
309
310 # Unpack work?
311 retrieved = unpack(format, got)[0]
312 self.assertEqual(x, retrieved)
313
314 # Adding any byte should cause a "too big" error.
315 self.assertRaises((struct.error, TypeError),
316 unpack, format, b'\x01' + got)
317
318 else:
319 # x is out of range -- verify pack realizes that.
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000320 self.assertRaises((struct.error, OverflowError),
321 pack, ">" + code, x)
322 self.assertRaises((struct.error, OverflowError),
323 pack, "<" + code, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000324
325 def run(self):
326 from random import randrange
327
328 # Create all interesting powers of 2.
329 values = []
330 for exp in range(self.bitsize + 3):
331 values.append(1 << exp)
332
333 # Add some random values.
334 for i in range(self.bitsize):
335 val = 0
336 for j in range(self.bytesize):
337 val = (val << 8) | randrange(256)
338 values.append(val)
339
340 # Try all those, and their negations, and +-1 from them. Note
341 # that this tests all power-of-2 boundaries in range, and a few out
342 # of range, plus +-(2**n +- 1).
343 for base in values:
344 for val in -base, base:
345 for incr in -1, 0, 1:
346 x = val + incr
347 try:
348 x = int(x)
349 except OverflowError:
350 pass
351 self.test_one(x)
352
353 # Some error cases.
354 for direction in "<>":
355 for code in self.formatpair:
356 for badobject in "a string", 3+42j, randrange:
357 self.assertRaises((struct.error, TypeError),
358 struct.pack, direction + code,
359 badobject)
360
361 for args in [("bB", 1),
362 ("hH", 2),
363 ("iI", 4),
364 ("lL", 4),
365 ("qQ", 8)]:
366 t = IntTester(*args)
367 t.run()
368
369 def test_p_code(self):
370 # Test p ("Pascal string") code.
371 for code, input, expected, expectedback in [
372 ('p','abc', '\x00', b''),
373 ('1p', 'abc', '\x00', b''),
374 ('2p', 'abc', '\x01a', b'a'),
375 ('3p', 'abc', '\x02ab', b'ab'),
376 ('4p', 'abc', '\x03abc', b'abc'),
377 ('5p', 'abc', '\x03abc\x00', b'abc'),
378 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
379 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
380 expected = bytes(expected, "latin-1")
381 got = struct.pack(code, input)
382 self.assertEqual(got, expected)
383 (got,) = struct.unpack(code, got)
384 self.assertEqual(got, expectedback)
385
386 def test_705836(self):
387 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
388 # from the low-order discarded bits could propagate into the exponent
389 # field, causing the result to be wrong by a factor of 2.
390 import math
391
392 for base in range(1, 33):
393 # smaller <- largest representable float less than base.
394 delta = 0.5
395 while base - delta / 2.0 != base:
396 delta /= 2.0
397 smaller = base - delta
398 # Packing this rounds away a solid string of trailing 1 bits.
399 packed = struct.pack("<f", smaller)
400 unpacked = struct.unpack("<f", packed)[0]
401 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
402 # 16, respectively.
403 self.assertEqual(base, unpacked)
404 bigpacked = struct.pack(">f", smaller)
405 self.assertEqual(bigpacked, string_reverse(packed))
406 unpacked = struct.unpack(">f", bigpacked)[0]
407 self.assertEqual(base, unpacked)
408
409 # Largest finite IEEE single.
410 big = (1 << 24) - 1
411 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000412 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000413 unpacked = struct.unpack(">f", packed)[0]
414 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000415
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000416 # The same, but tack on a 1 bit so it rounds up to infinity.
417 big = (1 << 25) - 1
418 big = math.ldexp(big, 127 - 24)
419 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000420
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000421 def test_1229380(self):
422 # SF bug 1229380. No struct.pack exception for some out of
423 # range integers
424 import sys
425 for endian in ('', '>', '<'):
426 for fmt in ('B', 'H', 'I', 'L'):
427 self.assertRaises((struct.error, OverflowError), struct.pack,
428 endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000429
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000430 self.assertRaises((struct.error, OverflowError), struct.pack,
431 endian + 'B', 300)
432 self.assertRaises((struct.error, OverflowError), struct.pack,
433 endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000434
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000435 self.assertRaises((struct.error, OverflowError), struct.pack,
436 endian + 'I', sys.maxsize * 4)
437 self.assertRaises((struct.error, OverflowError), struct.pack,
438 endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000439
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000440 def XXXtest_1530559(self):
441 # XXX This is broken: see the bug report
442 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
443 for endian in ('', '>', '<'):
444 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
445 self.check_float_coerce(endian + fmt, 1.0)
446 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 def test_unpack_from(self):
449 test_string = b'abcd01234'
450 fmt = '4s'
451 s = struct.Struct(fmt)
452 for cls in (bytes, bytearray):
453 data = cls(test_string)
454 if not isinstance(data, (bytes, bytearray)):
455 bytes_data = bytes(data, 'latin1')
456 else:
457 bytes_data = data
458 self.assertEqual(s.unpack_from(data), (b'abcd',))
459 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
460 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
461 for i in range(6):
462 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
463 for i in range(6, len(test_string) + 1):
464 self.assertRaises(struct.error, s.unpack_from, data, i)
465 for cls in (bytes, bytearray):
466 data = cls(test_string)
467 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
468 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
469 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
470 for i in range(6):
471 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
472 for i in range(6, len(test_string) + 1):
473 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000474
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000475 def test_pack_into(self):
476 test_string = b'Reykjavik rocks, eow!'
477 writable_buf = array.array('b', b' '*100)
478 fmt = '21s'
479 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000480
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000481 # Test without offset
482 s.pack_into(writable_buf, 0, test_string)
483 from_buf = writable_buf.tostring()[:len(test_string)]
484 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000485
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000486 # Test with offset.
487 s.pack_into(writable_buf, 10, test_string)
488 from_buf = writable_buf.tostring()[:len(test_string)+10]
489 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000490
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000491 # Go beyond boundaries.
492 small_buf = array.array('b', b' '*10)
493 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
494 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000495
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000496 # Test bogus offset (issue 3694)
497 sb = small_buf
498 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
499
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000500 def test_pack_into_fn(self):
501 test_string = b'Reykjavik rocks, eow!'
502 writable_buf = array.array('b', b' '*100)
503 fmt = '21s'
504 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000505
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000506 # Test without offset.
507 pack_into(writable_buf, 0, test_string)
508 from_buf = writable_buf.tostring()[:len(test_string)]
509 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000510
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000511 # Test with offset.
512 pack_into(writable_buf, 10, test_string)
513 from_buf = writable_buf.tostring()[:len(test_string)+10]
514 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000515
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000516 # Go beyond boundaries.
517 small_buf = array.array('b', b' '*10)
518 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
519 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000520
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000521 def test_unpack_with_buffer(self):
522 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
523 data1 = array.array('B', b'\x12\x34\x56\x78')
524 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
525 for data in [data1, data2]:
526 value, = struct.unpack('>I', data)
527 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000528
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000529 def test_bool(self):
530 for prefix in tuple("<>!=")+('',):
531 false = (), [], [], '', 0
532 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000533
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000534 falseFormat = prefix + '?' * len(false)
535 packedFalse = struct.pack(falseFormat, *false)
536 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000538 trueFormat = prefix + '?' * len(true)
539 packedTrue = struct.pack(trueFormat, *true)
540 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000541
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000542 self.assertEqual(len(true), len(unpackedTrue))
543 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000544
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000545 for t in unpackedFalse:
546 self.assertFalse(t)
547 for t in unpackedTrue:
548 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000549
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000550 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000551
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000552 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000553
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000554 if len(packed) != 1:
555 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
556 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000557
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000558 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
559 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000560
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000561 if IS32BIT:
562 def test_crasher(self):
563 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
564
565
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000566def test_main():
567 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000568
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000569if __name__ == '__main__':
570 test_main()