blob: bce8fdcfade5f891c9f5569d44bb7ab5b2636e27 [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
7from test.support import TestFailed, verbose, run_unittest, catch_warning
8
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:
17 PY_STRUCT_RANGE_CHECKING = 0
18 PY_STRUCT_OVERFLOW_MASKING = 1
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000020else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
22 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
23 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000024
Tim Peters17e17d42001-06-13 22:45:27 +000025def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000026 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000027
28def bigendian_to_native(value):
29 if ISBIGENDIAN:
30 return value
31 else:
32 return string_reverse(value)
33
Thomas Wouters0e3f5912006-08-11 14:57:12 +000034def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000035 @wraps(func)
36 def decorator(*args, **kw):
37 with catch_warning():
Thomas Wouters902d6eb2007-01-09 23:18:33 +000038 # Grrr, we need this function to warn every time. Without removing
39 # the warningregistry, running test_tarfile then test_struct would fail
40 # on 64-bit platforms.
Neal Norwitz221085d2007-02-25 20:55:47 +000041 globals = func.__globals__
Thomas Wouters902d6eb2007-01-09 23:18:33 +000042 if '__warningregistry__' in globals:
43 del globals['__warningregistry__']
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000044 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000045 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000046 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000047
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000048@with_warning_restore
Thomas Wouters0e3f5912006-08-11 14:57:12 +000049def deprecated_err(func, *args):
50 try:
51 func(*args)
52 except (struct.error, TypeError):
53 pass
54 except DeprecationWarning:
55 if not PY_STRUCT_OVERFLOW_MASKING:
Collin Winter3add4d72007-08-29 23:37:32 +000056 raise TestFailed("%s%s expected to raise struct.error" % (
57 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000058 else:
Collin Winter3add4d72007-08-29 23:37:32 +000059 raise TestFailed("%s%s did not raise error" % (
60 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000061
Tim Peters17e17d42001-06-13 22:45:27 +000062
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000063class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000064
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000065 @with_warning_restore
66 def check_float_coerce(self, format, number):
67 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
68 if PY_STRUCT_FLOAT_COERCE == 2:
69 # Test for pre-2.5 struct module
70 packed = struct.pack(format, number)
71 floored = struct.unpack(format, packed)[0]
72 self.assertEqual(floored, int(number),
73 "did not correcly coerce float to int")
74 return
75 try:
76 struct.pack(format, number)
77 except (struct.error, TypeError):
78 if PY_STRUCT_FLOAT_COERCE:
79 self.fail("expected DeprecationWarning for float coerce")
80 except DeprecationWarning:
81 if not PY_STRUCT_FLOAT_COERCE:
82 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000083 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000084 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000085
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000086 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000087 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000089 def test_consistence(self):
90 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000091
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000092 sz = struct.calcsize('i')
93 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000094
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000095 fmt = 'cbxxxxxxhhhhiillffd?'
96 fmt3 = '3c3b18x12h6i6l6f3d3?'
97 sz = struct.calcsize(fmt)
98 sz3 = struct.calcsize(fmt3)
99 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000100
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000101 self.assertRaises(struct.error, struct.pack, 'iii', 3)
102 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
103 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
104 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
105 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
106 s = struct.pack('ii', 1, 2)
107 self.assertRaises(struct.error, struct.unpack, 'iii', s)
108 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000109
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000110 def test_transitiveness(self):
111 c = b'a'
112 b = 1
113 h = 255
114 i = 65535
115 l = 65536
116 f = 3.1415
117 d = 3.1415
118 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000119
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000120 for prefix in ('', '@', '<', '>', '=', '!'):
121 for format in ('xcbhilfd?', 'xcBHILfd?'):
122 format = prefix + format
123 s = struct.pack(format, c, b, h, i, l, f, d, t)
124 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
125 self.assertEqual(cp, c)
126 self.assertEqual(bp, b)
127 self.assertEqual(hp, h)
128 self.assertEqual(ip, i)
129 self.assertEqual(lp, l)
130 self.assertEqual(int(100 * fp), int(100 * f))
131 self.assertEqual(int(100 * dp), int(100 * d))
132 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000133
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000134 def test_new_features(self):
135 # Test some of the new features in detail
136 # (format, argument, big-endian result, little-endian result, asymmetric)
137 tests = [
138 ('c', 'a', 'a', 'a', 0),
139 ('xc', 'a', '\0a', '\0a', 0),
140 ('cx', 'a', 'a\0', 'a\0', 0),
141 ('s', 'a', 'a', 'a', 0),
142 ('0s', 'helloworld', '', '', 1),
143 ('1s', 'helloworld', 'h', 'h', 1),
144 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
145 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
146 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
147 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
148 ('b', 7, '\7', '\7', 0),
149 ('b', -7, '\371', '\371', 0),
150 ('B', 7, '\7', '\7', 0),
151 ('B', 249, '\371', '\371', 0),
152 ('h', 700, '\002\274', '\274\002', 0),
153 ('h', -700, '\375D', 'D\375', 0),
154 ('H', 700, '\002\274', '\274\002', 0),
155 ('H', 0x10000-700, '\375D', 'D\375', 0),
156 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
157 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
158 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
159 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
160 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
161 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
162 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
163 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
164 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
165 ('d', 2.0, '@\000\000\000\000\000\000\000',
166 '\000\000\000\000\000\000\000@', 0),
167 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
168 ('d', -2.0, '\300\000\000\000\000\000\000\000',
169 '\000\000\000\000\000\000\000\300', 0),
170 ('?', 0, '\0', '\0', 0),
171 ('?', 3, '\1', '\1', 1),
172 ('?', True, '\1', '\1', 0),
173 ('?', [], '\0', '\0', 1),
174 ('?', (1,), '\1', '\1', 1),
175 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000176
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000177 for fmt, arg, big, lil, asy in tests:
178 big = bytes(big, "latin-1")
179 lil = bytes(lil, "latin-1")
180 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
181 ('='+fmt, ISBIGENDIAN and big or lil)]:
182 res = struct.pack(xfmt, arg)
183 self.assertEqual(res, exp)
184 self.assertEqual(struct.calcsize(xfmt), len(res))
185 rev = struct.unpack(xfmt, res)[0]
186 if isinstance(arg, str):
187 # Strings are returned as bytes since you can't know the
188 # encoding of the string when packed.
189 arg = bytes(arg, 'latin1')
190 if rev != arg:
191 self.assert_(asy)
192
193 def test_native_qQ(self):
194 # can't pack -1 as unsigned regardless
195 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
196 # can't pack string as 'q' regardless
197 self.assertRaises(struct.error, struct.pack, "q", "a")
198 # ditto, but 'Q'
199 self.assertRaises(struct.error, struct.pack, "Q", "a")
200
201 try:
202 struct.pack("q", 5)
203 except struct.error:
204 # does not have native q/Q
205 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000206 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000207 nbytes = struct.calcsize('q')
208 # The expected values here are in big-endian format, primarily
209 # because I'm on a little-endian machine and so this is the
210 # clearest way (for me) to force the code to get exercised.
211 for format, input, expected in (
212 ('q', -1, '\xff' * nbytes),
213 ('q', 0, '\x00' * nbytes),
214 ('Q', 0, '\x00' * nbytes),
215 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
216 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
217 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
218 expected = bytes(expected, "latin-1")
219 got = struct.pack(format, input)
220 native_expected = bigendian_to_native(expected)
221 self.assertEqual(got, native_expected)
222 retrieved = struct.unpack(format, got)[0]
223 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000224
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000225 def test_standard_integers(self):
226 # Standard integer tests (bBhHiIlLqQ).
227 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000228
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000229 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000230
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000231 # XXX Most std integer modes fail to test for out-of-range.
232 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
233 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
234 # reported by Mark Favas).
235 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000236
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000237 def __init__(self, formatpair, bytesize):
238 self.assertEqual(len(formatpair), 2)
239 self.formatpair = formatpair
240 for direction in "<>!=":
241 for code in formatpair:
242 format = direction + code
243 self.assertEqual(struct.calcsize(format), bytesize)
244 self.bytesize = bytesize
245 self.bitsize = bytesize * 8
246 self.signed_code, self.unsigned_code = formatpair
247 self.unsigned_min = 0
248 self.unsigned_max = 2**self.bitsize - 1
249 self.signed_min = -(2**(self.bitsize-1))
250 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000251
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000252 def test_one(self, x, pack=struct.pack,
253 unpack=struct.unpack,
254 unhexlify=binascii.unhexlify):
255 # Try signed.
256 code = self.signed_code
257 if self.signed_min <= x <= self.signed_max:
258 # Try big-endian.
259 expected = x
260 if x < 0:
261 expected += 1 << self.bitsize
262 self.assert_(expected > 0)
263 expected = hex(expected)[2:] # chop "0x"
264 if len(expected) & 1:
265 expected = "0" + expected
266 expected = unhexlify(expected)
267 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000268
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000269 # Pack work?
270 format = ">" + code
271 got = pack(format, x)
272 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000273
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000274 # Unpack work?
275 retrieved = unpack(format, got)[0]
276 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000277
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000278 # Adding any byte should cause a "too big" error.
279 self.assertRaises((struct.error, TypeError),
280 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000281
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000282 # Try little-endian.
283 format = "<" + code
284 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000285
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000286 # Pack work?
287 got = pack(format, x)
288 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000289
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000290 # Unpack work?
291 retrieved = unpack(format, got)[0]
292 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000293
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000294 # Adding any byte should cause a "too big" error.
295 self.assertRaises((struct.error, TypeError),
296 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000297
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000298 else:
299 # x is out of range -- verify pack realizes that.
300 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
301 if verbose:
302 print("Skipping buggy range check for code", code)
303 else:
304 deprecated_err(pack, ">" + code, x)
305 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000306
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000307 # Much the same for unsigned.
308 code = self.unsigned_code
309 if self.unsigned_min <= x <= self.unsigned_max:
310 # Try big-endian.
311 format = ">" + code
312 expected = x
313 expected = hex(expected)[2:] # chop "0x"
314 if len(expected) & 1:
315 expected = "0" + expected
316 expected = unhexlify(expected)
317 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000318
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000319 # Pack work?
320 got = pack(format, x)
321 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000322
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000323 # Unpack work?
324 retrieved = unpack(format, got)[0]
325 self.assertEqual(x, retrieved)
326
327 # Adding any byte should cause a "too big" error.
328 self.assertRaises((struct.error, TypeError),
329 unpack, format, b'\x01' + got)
330
331 # Try little-endian.
332 format = "<" + code
333 expected = string_reverse(expected)
334
335 # Pack work?
336 got = pack(format, x)
337 self.assertEqual(got, expected)
338
339 # Unpack work?
340 retrieved = unpack(format, got)[0]
341 self.assertEqual(x, retrieved)
342
343 # Adding any byte should cause a "too big" error.
344 self.assertRaises((struct.error, TypeError),
345 unpack, format, b'\x01' + got)
346
347 else:
348 # x is out of range -- verify pack realizes that.
349 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
350 if verbose:
351 print("Skipping buggy range check for code", code)
352 else:
353 deprecated_err(pack, ">" + code, x)
354 deprecated_err(pack, "<" + code, x)
355
356 def run(self):
357 from random import randrange
358
359 # Create all interesting powers of 2.
360 values = []
361 for exp in range(self.bitsize + 3):
362 values.append(1 << exp)
363
364 # Add some random values.
365 for i in range(self.bitsize):
366 val = 0
367 for j in range(self.bytesize):
368 val = (val << 8) | randrange(256)
369 values.append(val)
370
371 # Try all those, and their negations, and +-1 from them. Note
372 # that this tests all power-of-2 boundaries in range, and a few out
373 # of range, plus +-(2**n +- 1).
374 for base in values:
375 for val in -base, base:
376 for incr in -1, 0, 1:
377 x = val + incr
378 try:
379 x = int(x)
380 except OverflowError:
381 pass
382 self.test_one(x)
383
384 # Some error cases.
385 for direction in "<>":
386 for code in self.formatpair:
387 for badobject in "a string", 3+42j, randrange:
388 self.assertRaises((struct.error, TypeError),
389 struct.pack, direction + code,
390 badobject)
391
392 for args in [("bB", 1),
393 ("hH", 2),
394 ("iI", 4),
395 ("lL", 4),
396 ("qQ", 8)]:
397 t = IntTester(*args)
398 t.run()
399
400 def test_p_code(self):
401 # Test p ("Pascal string") code.
402 for code, input, expected, expectedback in [
403 ('p','abc', '\x00', b''),
404 ('1p', 'abc', '\x00', b''),
405 ('2p', 'abc', '\x01a', b'a'),
406 ('3p', 'abc', '\x02ab', b'ab'),
407 ('4p', 'abc', '\x03abc', b'abc'),
408 ('5p', 'abc', '\x03abc\x00', b'abc'),
409 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
410 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
411 expected = bytes(expected, "latin-1")
412 got = struct.pack(code, input)
413 self.assertEqual(got, expected)
414 (got,) = struct.unpack(code, got)
415 self.assertEqual(got, expectedback)
416
417 def test_705836(self):
418 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
419 # from the low-order discarded bits could propagate into the exponent
420 # field, causing the result to be wrong by a factor of 2.
421 import math
422
423 for base in range(1, 33):
424 # smaller <- largest representable float less than base.
425 delta = 0.5
426 while base - delta / 2.0 != base:
427 delta /= 2.0
428 smaller = base - delta
429 # Packing this rounds away a solid string of trailing 1 bits.
430 packed = struct.pack("<f", smaller)
431 unpacked = struct.unpack("<f", packed)[0]
432 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
433 # 16, respectively.
434 self.assertEqual(base, unpacked)
435 bigpacked = struct.pack(">f", smaller)
436 self.assertEqual(bigpacked, string_reverse(packed))
437 unpacked = struct.unpack(">f", bigpacked)[0]
438 self.assertEqual(base, unpacked)
439
440 # Largest finite IEEE single.
441 big = (1 << 24) - 1
442 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000443 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000444 unpacked = struct.unpack(">f", packed)[0]
445 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000446
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000447 # The same, but tack on a 1 bit so it rounds up to infinity.
448 big = (1 << 25) - 1
449 big = math.ldexp(big, 127 - 24)
450 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000451
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000452 if PY_STRUCT_RANGE_CHECKING:
453 def test_1229380(self):
454 # SF bug 1229380. No struct.pack exception for some out of
455 # range integers
456 import sys
457 for endian in ('', '>', '<'):
458 for fmt in ('B', 'H', 'I', 'L'):
459 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 deprecated_err(struct.pack, endian + 'B', 300)
462 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 deprecated_err(struct.pack, endian + 'I', sys.maxsize * 4)
465 deprecated_err(struct.pack, endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000466
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000467 def XXXtest_1530559(self):
468 # XXX This is broken: see the bug report
469 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
470 for endian in ('', '>', '<'):
471 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
472 self.check_float_coerce(endian + fmt, 1.0)
473 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000474
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000475 def test_unpack_from(self):
476 test_string = b'abcd01234'
477 fmt = '4s'
478 s = struct.Struct(fmt)
479 for cls in (bytes, bytearray):
480 data = cls(test_string)
481 if not isinstance(data, (bytes, bytearray)):
482 bytes_data = bytes(data, 'latin1')
483 else:
484 bytes_data = data
485 self.assertEqual(s.unpack_from(data), (b'abcd',))
486 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
487 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
488 for i in range(6):
489 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
490 for i in range(6, len(test_string) + 1):
491 self.assertRaises(struct.error, s.unpack_from, data, i)
492 for cls in (bytes, bytearray):
493 data = cls(test_string)
494 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
495 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
496 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
497 for i in range(6):
498 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
499 for i in range(6, len(test_string) + 1):
500 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 def test_pack_into(self):
503 test_string = b'Reykjavik rocks, eow!'
504 writable_buf = array.array('b', b' '*100)
505 fmt = '21s'
506 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000507
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000508 # Test without offset
509 s.pack_into(writable_buf, 0, test_string)
510 from_buf = writable_buf.tostring()[:len(test_string)]
511 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000512
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000513 # Test with offset.
514 s.pack_into(writable_buf, 10, test_string)
515 from_buf = writable_buf.tostring()[:len(test_string)+10]
516 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000517
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000518 # Go beyond boundaries.
519 small_buf = array.array('b', b' '*10)
520 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
521 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000522
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000523 def test_pack_into_fn(self):
524 test_string = b'Reykjavik rocks, eow!'
525 writable_buf = array.array('b', b' '*100)
526 fmt = '21s'
527 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000528
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000529 # Test without offset.
530 pack_into(writable_buf, 0, test_string)
531 from_buf = writable_buf.tostring()[:len(test_string)]
532 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000533
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000534 # Test with offset.
535 pack_into(writable_buf, 10, test_string)
536 from_buf = writable_buf.tostring()[:len(test_string)+10]
537 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000538
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000539 # Go beyond boundaries.
540 small_buf = array.array('b', b' '*10)
541 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
542 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000543
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000544 def test_unpack_with_buffer(self):
545 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
546 data1 = array.array('B', b'\x12\x34\x56\x78')
547 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
548 for data in [data1, data2]:
549 value, = struct.unpack('>I', data)
550 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000551
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000552 def test_bool(self):
553 for prefix in tuple("<>!=")+('',):
554 false = (), [], [], '', 0
555 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000556
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000557 falseFormat = prefix + '?' * len(false)
558 packedFalse = struct.pack(falseFormat, *false)
559 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000560
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000561 trueFormat = prefix + '?' * len(true)
562 packedTrue = struct.pack(trueFormat, *true)
563 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000564
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000565 self.assertEqual(len(true), len(unpackedTrue))
566 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000567
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000568 for t in unpackedFalse:
569 self.assertFalse(t)
570 for t in unpackedTrue:
571 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000572
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000573 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000574
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000575 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000576
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000577 if len(packed) != 1:
578 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
579 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000580
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000581 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
582 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000583
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000584 if IS32BIT:
585 def test_crasher(self):
586 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
587
588
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000589def test_main():
590 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000591
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000592if __name__ == '__main__':
593 test_main()