blob: bdbc397415cbc23b7092b56fb4e0fbf9fbef9d74 [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
Georg Brandlb1441c72009-01-03 22:33:39 +00005warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
6 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00007
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00008from functools import wraps
Brett Cannon1cd02472008-09-09 01:52:27 +00009from test.support import TestFailed, verbose, run_unittest
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000010
Tim Peters17e17d42001-06-13 22:45:27 +000011import sys
12ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +000013IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000014del sys
Tim Peters17e17d42001-06-13 22:45:27 +000015
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000016try:
17 import _struct
18except ImportError:
19 PY_STRUCT_RANGE_CHECKING = 0
20 PY_STRUCT_OVERFLOW_MASKING = 1
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000022else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000023 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
24 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
25 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000026
Tim Peters17e17d42001-06-13 22:45:27 +000027def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000028 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000029
30def bigendian_to_native(value):
31 if ISBIGENDIAN:
32 return value
33 else:
34 return string_reverse(value)
35
Thomas Wouters0e3f5912006-08-11 14:57:12 +000036def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000037 @wraps(func)
38 def decorator(*args, **kw):
Brett Cannon1cd02472008-09-09 01:52:27 +000039 with warnings.catch_warnings():
Nick Coghlanb1304932008-07-13 12:25:08 +000040 # We need this function to warn every time, so stick an
41 # unqualifed 'always' at the head of the filter list
42 warnings.simplefilter("always")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000044 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000045 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000046
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000047@with_warning_restore
Thomas Wouters0e3f5912006-08-11 14:57:12 +000048def deprecated_err(func, *args):
49 try:
50 func(*args)
51 except (struct.error, TypeError):
52 pass
53 except DeprecationWarning:
54 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlanb1304932008-07-13 12:25:08 +000055 raise TestFailed("%s%s expected to raise DeprecationWarning" % (
Collin Winter3add4d72007-08-29 23:37:32 +000056 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000057 else:
Collin Winter3add4d72007-08-29 23:37:32 +000058 raise TestFailed("%s%s did not raise error" % (
59 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000060
Tim Peters17e17d42001-06-13 22:45:27 +000061
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000063
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000064 @with_warning_restore
65 def check_float_coerce(self, format, number):
66 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
67 if PY_STRUCT_FLOAT_COERCE == 2:
68 # Test for pre-2.5 struct module
69 packed = struct.pack(format, number)
70 floored = struct.unpack(format, packed)[0]
71 self.assertEqual(floored, int(number),
72 "did not correcly coerce float to int")
73 return
74 try:
75 struct.pack(format, number)
76 except (struct.error, TypeError):
77 if PY_STRUCT_FLOAT_COERCE:
78 self.fail("expected DeprecationWarning for float coerce")
79 except DeprecationWarning:
80 if not PY_STRUCT_FLOAT_COERCE:
81 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000082 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000083 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000085 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000086 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000088 def test_consistence(self):
89 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000091 sz = struct.calcsize('i')
92 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000094 fmt = 'cbxxxxxxhhhhiillffd?'
95 fmt3 = '3c3b18x12h6i6l6f3d3?'
96 sz = struct.calcsize(fmt)
97 sz3 = struct.calcsize(fmt3)
98 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000099
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000100 self.assertRaises(struct.error, struct.pack, 'iii', 3)
101 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
102 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
103 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
104 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
105 s = struct.pack('ii', 1, 2)
106 self.assertRaises(struct.error, struct.unpack, 'iii', s)
107 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000108
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000109 def test_transitiveness(self):
110 c = b'a'
111 b = 1
112 h = 255
113 i = 65535
114 l = 65536
115 f = 3.1415
116 d = 3.1415
117 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000118
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000119 for prefix in ('', '@', '<', '>', '=', '!'):
120 for format in ('xcbhilfd?', 'xcBHILfd?'):
121 format = prefix + format
122 s = struct.pack(format, c, b, h, i, l, f, d, t)
123 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
124 self.assertEqual(cp, c)
125 self.assertEqual(bp, b)
126 self.assertEqual(hp, h)
127 self.assertEqual(ip, i)
128 self.assertEqual(lp, l)
129 self.assertEqual(int(100 * fp), int(100 * f))
130 self.assertEqual(int(100 * dp), int(100 * d))
131 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000132
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000133 def test_new_features(self):
134 # Test some of the new features in detail
135 # (format, argument, big-endian result, little-endian result, asymmetric)
136 tests = [
137 ('c', 'a', 'a', 'a', 0),
138 ('xc', 'a', '\0a', '\0a', 0),
139 ('cx', 'a', 'a\0', 'a\0', 0),
140 ('s', 'a', 'a', 'a', 0),
141 ('0s', 'helloworld', '', '', 1),
142 ('1s', 'helloworld', 'h', 'h', 1),
143 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
144 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
145 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
146 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
147 ('b', 7, '\7', '\7', 0),
148 ('b', -7, '\371', '\371', 0),
149 ('B', 7, '\7', '\7', 0),
150 ('B', 249, '\371', '\371', 0),
151 ('h', 700, '\002\274', '\274\002', 0),
152 ('h', -700, '\375D', 'D\375', 0),
153 ('H', 700, '\002\274', '\274\002', 0),
154 ('H', 0x10000-700, '\375D', 'D\375', 0),
155 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
156 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
158 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
159 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
160 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
161 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
162 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
163 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
164 ('d', 2.0, '@\000\000\000\000\000\000\000',
165 '\000\000\000\000\000\000\000@', 0),
166 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
167 ('d', -2.0, '\300\000\000\000\000\000\000\000',
168 '\000\000\000\000\000\000\000\300', 0),
169 ('?', 0, '\0', '\0', 0),
170 ('?', 3, '\1', '\1', 1),
171 ('?', True, '\1', '\1', 0),
172 ('?', [], '\0', '\0', 1),
173 ('?', (1,), '\1', '\1', 1),
174 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000175
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000176 for fmt, arg, big, lil, asy in tests:
177 big = bytes(big, "latin-1")
178 lil = bytes(lil, "latin-1")
179 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
180 ('='+fmt, ISBIGENDIAN and big or lil)]:
181 res = struct.pack(xfmt, arg)
182 self.assertEqual(res, exp)
183 self.assertEqual(struct.calcsize(xfmt), len(res))
184 rev = struct.unpack(xfmt, res)[0]
185 if isinstance(arg, str):
186 # Strings are returned as bytes since you can't know the
187 # encoding of the string when packed.
188 arg = bytes(arg, 'latin1')
189 if rev != arg:
190 self.assert_(asy)
191
192 def test_native_qQ(self):
193 # can't pack -1 as unsigned regardless
194 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
195 # can't pack string as 'q' regardless
196 self.assertRaises(struct.error, struct.pack, "q", "a")
197 # ditto, but 'Q'
198 self.assertRaises(struct.error, struct.pack, "Q", "a")
199
200 try:
201 struct.pack("q", 5)
202 except struct.error:
203 # does not have native q/Q
204 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000205 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000206 nbytes = struct.calcsize('q')
207 # The expected values here are in big-endian format, primarily
208 # because I'm on a little-endian machine and so this is the
209 # clearest way (for me) to force the code to get exercised.
210 for format, input, expected in (
211 ('q', -1, '\xff' * nbytes),
212 ('q', 0, '\x00' * nbytes),
213 ('Q', 0, '\x00' * nbytes),
214 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
215 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
216 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
217 expected = bytes(expected, "latin-1")
218 got = struct.pack(format, input)
219 native_expected = bigendian_to_native(expected)
220 self.assertEqual(got, native_expected)
221 retrieved = struct.unpack(format, got)[0]
222 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 def test_standard_integers(self):
225 # Standard integer tests (bBhHiIlLqQ).
226 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000229
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000230 # XXX Most std integer modes fail to test for out-of-range.
231 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
232 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
233 # reported by Mark Favas).
234 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000235
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000236 def __init__(self, formatpair, bytesize):
237 self.assertEqual(len(formatpair), 2)
238 self.formatpair = formatpair
239 for direction in "<>!=":
240 for code in formatpair:
241 format = direction + code
242 self.assertEqual(struct.calcsize(format), bytesize)
243 self.bytesize = bytesize
244 self.bitsize = bytesize * 8
245 self.signed_code, self.unsigned_code = formatpair
246 self.unsigned_min = 0
247 self.unsigned_max = 2**self.bitsize - 1
248 self.signed_min = -(2**(self.bitsize-1))
249 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000250
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000251 def test_one(self, x, pack=struct.pack,
252 unpack=struct.unpack,
253 unhexlify=binascii.unhexlify):
254 # Try signed.
255 code = self.signed_code
256 if self.signed_min <= x <= self.signed_max:
257 # Try big-endian.
258 expected = x
259 if x < 0:
260 expected += 1 << self.bitsize
261 self.assert_(expected > 0)
262 expected = hex(expected)[2:] # chop "0x"
263 if len(expected) & 1:
264 expected = "0" + expected
265 expected = unhexlify(expected)
266 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000267
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268 # Pack work?
269 format = ">" + code
270 got = pack(format, x)
271 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000272
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000273 # Unpack work?
274 retrieved = unpack(format, got)[0]
275 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000276
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000277 # Adding any byte should cause a "too big" error.
278 self.assertRaises((struct.error, TypeError),
279 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000280
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000281 # Try little-endian.
282 format = "<" + code
283 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000284
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000285 # Pack work?
286 got = pack(format, x)
287 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000288
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000289 # Unpack work?
290 retrieved = unpack(format, got)[0]
291 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000292
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000293 # Adding any byte should cause a "too big" error.
294 self.assertRaises((struct.error, TypeError),
295 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000296
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000297 else:
298 # x is out of range -- verify pack realizes that.
299 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
300 if verbose:
301 print("Skipping buggy range check for code", code)
302 else:
303 deprecated_err(pack, ">" + code, x)
304 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000305
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000306 # Much the same for unsigned.
307 code = self.unsigned_code
308 if self.unsigned_min <= x <= self.unsigned_max:
309 # Try big-endian.
310 format = ">" + code
311 expected = x
312 expected = hex(expected)[2:] # chop "0x"
313 if len(expected) & 1:
314 expected = "0" + expected
315 expected = unhexlify(expected)
316 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000317
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000318 # Pack work?
319 got = pack(format, x)
320 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000321
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000322 # Unpack work?
323 retrieved = unpack(format, got)[0]
324 self.assertEqual(x, retrieved)
325
326 # Adding any byte should cause a "too big" error.
327 self.assertRaises((struct.error, TypeError),
328 unpack, format, b'\x01' + got)
329
330 # Try little-endian.
331 format = "<" + code
332 expected = string_reverse(expected)
333
334 # Pack work?
335 got = pack(format, x)
336 self.assertEqual(got, expected)
337
338 # Unpack work?
339 retrieved = unpack(format, got)[0]
340 self.assertEqual(x, retrieved)
341
342 # Adding any byte should cause a "too big" error.
343 self.assertRaises((struct.error, TypeError),
344 unpack, format, b'\x01' + got)
345
346 else:
347 # x is out of range -- verify pack realizes that.
348 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
349 if verbose:
350 print("Skipping buggy range check for code", code)
351 else:
352 deprecated_err(pack, ">" + code, x)
353 deprecated_err(pack, "<" + code, x)
354
355 def run(self):
356 from random import randrange
357
358 # Create all interesting powers of 2.
359 values = []
360 for exp in range(self.bitsize + 3):
361 values.append(1 << exp)
362
363 # Add some random values.
364 for i in range(self.bitsize):
365 val = 0
366 for j in range(self.bytesize):
367 val = (val << 8) | randrange(256)
368 values.append(val)
369
370 # Try all those, and their negations, and +-1 from them. Note
371 # that this tests all power-of-2 boundaries in range, and a few out
372 # of range, plus +-(2**n +- 1).
373 for base in values:
374 for val in -base, base:
375 for incr in -1, 0, 1:
376 x = val + incr
377 try:
378 x = int(x)
379 except OverflowError:
380 pass
381 self.test_one(x)
382
383 # Some error cases.
384 for direction in "<>":
385 for code in self.formatpair:
386 for badobject in "a string", 3+42j, randrange:
387 self.assertRaises((struct.error, TypeError),
388 struct.pack, direction + code,
389 badobject)
390
391 for args in [("bB", 1),
392 ("hH", 2),
393 ("iI", 4),
394 ("lL", 4),
395 ("qQ", 8)]:
396 t = IntTester(*args)
397 t.run()
398
399 def test_p_code(self):
400 # Test p ("Pascal string") code.
401 for code, input, expected, expectedback in [
402 ('p','abc', '\x00', b''),
403 ('1p', 'abc', '\x00', b''),
404 ('2p', 'abc', '\x01a', b'a'),
405 ('3p', 'abc', '\x02ab', b'ab'),
406 ('4p', 'abc', '\x03abc', b'abc'),
407 ('5p', 'abc', '\x03abc\x00', b'abc'),
408 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
409 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
410 expected = bytes(expected, "latin-1")
411 got = struct.pack(code, input)
412 self.assertEqual(got, expected)
413 (got,) = struct.unpack(code, got)
414 self.assertEqual(got, expectedback)
415
416 def test_705836(self):
417 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
418 # from the low-order discarded bits could propagate into the exponent
419 # field, causing the result to be wrong by a factor of 2.
420 import math
421
422 for base in range(1, 33):
423 # smaller <- largest representable float less than base.
424 delta = 0.5
425 while base - delta / 2.0 != base:
426 delta /= 2.0
427 smaller = base - delta
428 # Packing this rounds away a solid string of trailing 1 bits.
429 packed = struct.pack("<f", smaller)
430 unpacked = struct.unpack("<f", packed)[0]
431 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
432 # 16, respectively.
433 self.assertEqual(base, unpacked)
434 bigpacked = struct.pack(">f", smaller)
435 self.assertEqual(bigpacked, string_reverse(packed))
436 unpacked = struct.unpack(">f", bigpacked)[0]
437 self.assertEqual(base, unpacked)
438
439 # Largest finite IEEE single.
440 big = (1 << 24) - 1
441 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000442 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000443 unpacked = struct.unpack(">f", packed)[0]
444 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000445
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000446 # The same, but tack on a 1 bit so it rounds up to infinity.
447 big = (1 << 25) - 1
448 big = math.ldexp(big, 127 - 24)
449 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000450
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000451 if PY_STRUCT_RANGE_CHECKING:
452 def test_1229380(self):
453 # SF bug 1229380. No struct.pack exception for some out of
454 # range integers
455 import sys
456 for endian in ('', '>', '<'):
457 for fmt in ('B', 'H', 'I', 'L'):
458 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000459
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000460 deprecated_err(struct.pack, endian + 'B', 300)
461 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000463 deprecated_err(struct.pack, endian + 'I', sys.maxsize * 4)
464 deprecated_err(struct.pack, endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 def XXXtest_1530559(self):
467 # XXX This is broken: see the bug report
468 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
469 for endian in ('', '>', '<'):
470 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
471 self.check_float_coerce(endian + fmt, 1.0)
472 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000473
Georg Brandlb1441c72009-01-03 22:33:39 +0000474 def test_issue4228(self):
475 # Packing a long may yield either 32 or 64 bits
476 x = struct.pack('L', -1)[:4]
477 self.assertEqual(x, b'\xff'*4)
478
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000479 def test_unpack_from(self):
480 test_string = b'abcd01234'
481 fmt = '4s'
482 s = struct.Struct(fmt)
483 for cls in (bytes, bytearray):
484 data = cls(test_string)
485 if not isinstance(data, (bytes, bytearray)):
486 bytes_data = bytes(data, 'latin1')
487 else:
488 bytes_data = data
489 self.assertEqual(s.unpack_from(data), (b'abcd',))
490 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
491 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
492 for i in range(6):
493 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
494 for i in range(6, len(test_string) + 1):
495 self.assertRaises(struct.error, s.unpack_from, data, i)
496 for cls in (bytes, bytearray):
497 data = cls(test_string)
498 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
499 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
500 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
501 for i in range(6):
502 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
503 for i in range(6, len(test_string) + 1):
504 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000505
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000506 def test_pack_into(self):
507 test_string = b'Reykjavik rocks, eow!'
508 writable_buf = array.array('b', b' '*100)
509 fmt = '21s'
510 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 # Test without offset
513 s.pack_into(writable_buf, 0, test_string)
514 from_buf = writable_buf.tostring()[:len(test_string)]
515 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000516
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000517 # Test with offset.
518 s.pack_into(writable_buf, 10, test_string)
519 from_buf = writable_buf.tostring()[:len(test_string)+10]
520 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000521
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000522 # Go beyond boundaries.
523 small_buf = array.array('b', b' '*10)
524 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
525 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000526
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000527 def test_pack_into_fn(self):
528 test_string = b'Reykjavik rocks, eow!'
529 writable_buf = array.array('b', b' '*100)
530 fmt = '21s'
531 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000532
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000533 # Test without offset.
534 pack_into(writable_buf, 0, test_string)
535 from_buf = writable_buf.tostring()[:len(test_string)]
536 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000538 # Test with offset.
539 pack_into(writable_buf, 10, test_string)
540 from_buf = writable_buf.tostring()[:len(test_string)+10]
541 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000542
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000543 # Go beyond boundaries.
544 small_buf = array.array('b', b' '*10)
545 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
546 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000547
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000548 def test_unpack_with_buffer(self):
549 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
550 data1 = array.array('B', b'\x12\x34\x56\x78')
551 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
552 for data in [data1, data2]:
553 value, = struct.unpack('>I', data)
554 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000555
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000556 def test_bool(self):
557 for prefix in tuple("<>!=")+('',):
558 false = (), [], [], '', 0
559 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000560
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000561 falseFormat = prefix + '?' * len(false)
562 packedFalse = struct.pack(falseFormat, *false)
563 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000564
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000565 trueFormat = prefix + '?' * len(true)
566 packedTrue = struct.pack(trueFormat, *true)
567 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000568
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000569 self.assertEqual(len(true), len(unpackedTrue))
570 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000571
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000572 for t in unpackedFalse:
573 self.assertFalse(t)
574 for t in unpackedTrue:
575 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000576
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000577 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000578
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000579 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000580
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000581 if len(packed) != 1:
582 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
583 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000584
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000585 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
586 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000587
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000588 if IS32BIT:
589 def test_crasher(self):
590 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
591
592
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000593def test_main():
594 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000595
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000596if __name__ == '__main__':
597 test_main()