blob: c0104926a251d0104968668baee8dcdf038ad76a [file] [log] [blame]
Martin Blais2856e5f2006-05-26 12:03:27 +00001import array
Benjamin Petersond5299862008-06-11 01:31:28 +00002import unittest
3import struct
Bob Ippolito2fd39772006-05-29 22:55:48 +00004import warnings
Mark Dickinsone9a5a542010-04-06 15:19:40 +00005import inspect
Georg Brandl47fe9812009-01-01 15:46:10 +00006warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
7 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00008
Benjamin Petersond5299862008-06-11 01:31:28 +00009from functools import wraps
Brett Cannon672237d2008-09-09 00:49:16 +000010from test.test_support import TestFailed, verbose, run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +000011
Tim Peters17e17d42001-06-13 22:45:27 +000012import sys
13ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000014IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000015
Bob Ippolito2fd39772006-05-29 22:55:48 +000016try:
17 import _struct
18except ImportError:
19 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000020 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000021 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000022else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +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)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000026
Tim Peters17e17d42001-06-13 22:45:27 +000027def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000028 return "".join(reversed(s))
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
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000036def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000037 @wraps(func)
38 def decorator(*args, **kw):
Brett Cannon672237d2008-09-09 00:49:16 +000039 with warnings.catch_warnings():
Nick Coghlan38469e22008-07-13 12:23:47 +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")
Benjamin Petersond5299862008-06-11 01:31:28 +000043 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000044 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000045 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000046
Benjamin Petersond5299862008-06-11 01:31:28 +000047@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +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 Coghlan38469e22008-07-13 12:23:47 +000055 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000056 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000057 else:
58 raise TestFailed, "%s%s did not raise error" % (
59 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000060
Tim Peters17e17d42001-06-13 22:45:27 +000061
Benjamin Petersond5299862008-06-11 01:31:28 +000062class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000063
Benjamin Petersond5299862008-06-11 01:31:28 +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:
Benjamin Petersond5299862008-06-11 01:31:28 +000083 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Benjamin Petersond5299862008-06-11 01:31:28 +000085 def test_isbigendian(self):
86 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Benjamin Petersond5299862008-06-11 01:31:28 +000088 def test_consistence(self):
89 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Benjamin Petersond5299862008-06-11 01:31:28 +000091 sz = struct.calcsize('i')
92 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Benjamin Petersond5299862008-06-11 01:31:28 +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
Benjamin Petersond5299862008-06-11 01:31:28 +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', '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
Mark Dickinsone9a5a542010-04-06 15:19:40 +0000109 def test_warnings_stacklevel(self):
110 # Python versions between 2.6 and 2.6.5 were producing
111 # warning messages at the wrong stacklevel.
112 def inner(fn, *args):
113 return inspect.currentframe().f_lineno, fn(*args)
114
115 def check_warning_stacklevel(fn, *args):
116 with warnings.catch_warnings(record=True) as w:
117 # "always" to make sure __warningregistry__ isn't affected
118 warnings.simplefilter("always")
119 lineno, result = inner(fn, *args)
120 for warn in w:
121 self.assertEqual(warn.lineno, lineno)
122
123 # out of range warnings
124 check_warning_stacklevel(struct.pack, '<L', -1)
125 check_warning_stacklevel(struct.pack, 'L', -1)
126 check_warning_stacklevel(struct.pack, '<h', 65536)
127 check_warning_stacklevel(struct.pack, '<l', 2**100)
128
129 # float warnings
130 check_warning_stacklevel(struct.pack, 'L', 3.1)
131
Benjamin Petersond5299862008-06-11 01:31:28 +0000132 def test_transitiveness(self):
133 c = 'a'
134 b = 1
135 h = 255
136 i = 65535
137 l = 65536
138 f = 3.1415
139 d = 3.1415
140 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000141
Benjamin Petersond5299862008-06-11 01:31:28 +0000142 for prefix in ('', '@', '<', '>', '=', '!'):
143 for format in ('xcbhilfd?', 'xcBHILfd?'):
144 format = prefix + format
145 s = struct.pack(format, c, b, h, i, l, f, d, t)
146 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
147 self.assertEqual(cp, c)
148 self.assertEqual(bp, b)
149 self.assertEqual(hp, h)
150 self.assertEqual(ip, i)
151 self.assertEqual(lp, l)
152 self.assertEqual(int(100 * fp), int(100 * f))
153 self.assertEqual(int(100 * dp), int(100 * d))
154 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000155
Benjamin Petersond5299862008-06-11 01:31:28 +0000156 def test_new_features(self):
157 # Test some of the new features in detail
158 # (format, argument, big-endian result, little-endian result, asymmetric)
159 tests = [
160 ('c', 'a', 'a', 'a', 0),
161 ('xc', 'a', '\0a', '\0a', 0),
162 ('cx', 'a', 'a\0', 'a\0', 0),
163 ('s', 'a', 'a', 'a', 0),
164 ('0s', 'helloworld', '', '', 1),
165 ('1s', 'helloworld', 'h', 'h', 1),
166 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
167 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
168 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
169 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
170 ('b', 7, '\7', '\7', 0),
171 ('b', -7, '\371', '\371', 0),
172 ('B', 7, '\7', '\7', 0),
173 ('B', 249, '\371', '\371', 0),
174 ('h', 700, '\002\274', '\274\002', 0),
175 ('h', -700, '\375D', 'D\375', 0),
176 ('H', 700, '\002\274', '\274\002', 0),
177 ('H', 0x10000-700, '\375D', 'D\375', 0),
178 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
179 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
180 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
181 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
182 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
183 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
184 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
185 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
186 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
187 ('d', 2.0, '@\000\000\000\000\000\000\000',
188 '\000\000\000\000\000\000\000@', 0),
189 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
190 ('d', -2.0, '\300\000\000\000\000\000\000\000',
191 '\000\000\000\000\000\000\000\300', 0),
192 ('?', 0, '\0', '\0', 0),
193 ('?', 3, '\1', '\1', 1),
194 ('?', True, '\1', '\1', 0),
195 ('?', [], '\0', '\0', 1),
196 ('?', (1,), '\1', '\1', 1),
197 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000198
Benjamin Petersond5299862008-06-11 01:31:28 +0000199 for fmt, arg, big, lil, asy in tests:
200 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
201 ('='+fmt, ISBIGENDIAN and big or lil)]:
202 res = struct.pack(xfmt, arg)
203 self.assertEqual(res, exp)
204 self.assertEqual(struct.calcsize(xfmt), len(res))
205 rev = struct.unpack(xfmt, res)[0]
206 if rev != arg:
207 self.assert_(asy)
208
209 def test_native_qQ(self):
210 # can't pack -1 as unsigned regardless
211 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
212 # can't pack string as 'q' regardless
213 self.assertRaises(struct.error, struct.pack, "q", "a")
214 # ditto, but 'Q'
215 self.assertRaises(struct.error, struct.pack, "Q", "a")
216
217 try:
218 struct.pack("q", 5)
219 except struct.error:
220 # does not have native q/Q
221 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000222 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000223 bytes = struct.calcsize('q')
224 # The expected values here are in big-endian format, primarily
225 # because I'm on a little-endian machine and so this is the
226 # clearest way (for me) to force the code to get exercised.
227 for format, input, expected in (
228 ('q', -1, '\xff' * bytes),
229 ('q', 0, '\x00' * bytes),
230 ('Q', 0, '\x00' * bytes),
231 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
232 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
233 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
234 got = struct.pack(format, input)
235 native_expected = bigendian_to_native(expected)
236 self.assertEqual(got, native_expected)
237 retrieved = struct.unpack(format, got)[0]
238 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000239
Benjamin Petersond5299862008-06-11 01:31:28 +0000240 def test_standard_integers(self):
241 # Standard integer tests (bBhHiIlLqQ).
242 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000243
Benjamin Petersond5299862008-06-11 01:31:28 +0000244 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000245
Benjamin Petersond5299862008-06-11 01:31:28 +0000246 # XXX Most std integer modes fail to test for out-of-range.
247 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
248 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
249 # reported by Mark Favas).
250 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000251
Benjamin Petersond5299862008-06-11 01:31:28 +0000252 def __init__(self, formatpair, bytesize):
253 self.assertEqual(len(formatpair), 2)
254 self.formatpair = formatpair
255 for direction in "<>!=":
256 for code in formatpair:
257 format = direction + code
258 self.assertEqual(struct.calcsize(format), bytesize)
259 self.bytesize = bytesize
260 self.bitsize = bytesize * 8
261 self.signed_code, self.unsigned_code = formatpair
262 self.unsigned_min = 0
263 self.unsigned_max = 2L**self.bitsize - 1
264 self.signed_min = -(2L**(self.bitsize-1))
265 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000266
Benjamin Petersond5299862008-06-11 01:31:28 +0000267 def test_one(self, x, pack=struct.pack,
268 unpack=struct.unpack,
269 unhexlify=binascii.unhexlify):
270 # Try signed.
271 code = self.signed_code
272 if self.signed_min <= x <= self.signed_max:
273 # Try big-endian.
274 expected = long(x)
275 if x < 0:
276 expected += 1L << self.bitsize
277 self.assert_(expected > 0)
278 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
279 if len(expected) & 1:
280 expected = "0" + expected
281 expected = unhexlify(expected)
282 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000283
Benjamin Petersond5299862008-06-11 01:31:28 +0000284 # Pack work?
285 format = ">" + code
286 got = pack(format, x)
287 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000288
Benjamin Petersond5299862008-06-11 01:31:28 +0000289 # Unpack work?
290 retrieved = unpack(format, got)[0]
291 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000292
Benjamin Petersond5299862008-06-11 01:31:28 +0000293 # Adding any byte should cause a "too big" error.
294 self.assertRaises((struct.error, TypeError), unpack, format,
295 '\x01' + got)
296 # Try little-endian.
297 format = "<" + code
298 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000299
Benjamin Petersond5299862008-06-11 01:31:28 +0000300 # Pack work?
301 got = pack(format, x)
302 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000303
Benjamin Petersond5299862008-06-11 01:31:28 +0000304 # Unpack work?
305 retrieved = unpack(format, got)[0]
306 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000307
Benjamin Petersond5299862008-06-11 01:31:28 +0000308 # Adding any byte should cause a "too big" error.
309 self.assertRaises((struct.error, TypeError), unpack, format,
310 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000311
Benjamin Petersond5299862008-06-11 01:31:28 +0000312 else:
313 # x is out of range -- verify pack realizes that.
314 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
315 if verbose:
316 print "Skipping buggy range check for code", code
317 else:
318 deprecated_err(pack, ">" + code, x)
319 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000320
Benjamin Petersond5299862008-06-11 01:31:28 +0000321 # Much the same for unsigned.
322 code = self.unsigned_code
323 if self.unsigned_min <= x <= self.unsigned_max:
324 # Try big-endian.
325 format = ">" + code
326 expected = long(x)
327 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
328 if len(expected) & 1:
329 expected = "0" + expected
330 expected = unhexlify(expected)
331 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000332
Benjamin Petersond5299862008-06-11 01:31:28 +0000333 # Pack work?
334 got = pack(format, x)
335 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000336
Benjamin Petersond5299862008-06-11 01:31:28 +0000337 # Unpack work?
338 retrieved = unpack(format, got)[0]
339 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000340
Benjamin Petersond5299862008-06-11 01:31:28 +0000341 # Adding any byte should cause a "too big" error.
342 self.assertRaises((struct.error, TypeError), unpack, format,
343 '\x01' + got)
344
345 # Try little-endian.
346 format = "<" + code
347 expected = string_reverse(expected)
348
349 # Pack work?
350 got = pack(format, x)
351 self.assertEqual(got, expected)
352
353 # Unpack work?
354 retrieved = unpack(format, got)[0]
355 self.assertEqual(x, retrieved)
356
357 # Adding any byte should cause a "too big" error.
358 self.assertRaises((struct.error, TypeError), unpack, format,
359 '\x01' + got)
360
361 else:
362 # x is out of range -- verify pack realizes that.
363 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
364 if verbose:
365 print "Skipping buggy range check for code", code
366 else:
367 deprecated_err(pack, ">" + code, x)
368 deprecated_err(pack, "<" + code, x)
369
370 def run(self):
371 from random import randrange
372
373 # Create all interesting powers of 2.
374 values = []
375 for exp in range(self.bitsize + 3):
376 values.append(1L << exp)
377
378 # Add some random values.
379 for i in range(self.bitsize):
380 val = 0L
381 for j in range(self.bytesize):
382 val = (val << 8) | randrange(256)
383 values.append(val)
384
385 # Try all those, and their negations, and +-1 from them. Note
386 # that this tests all power-of-2 boundaries in range, and a few out
387 # of range, plus +-(2**n +- 1).
388 for base in values:
389 for val in -base, base:
390 for incr in -1, 0, 1:
391 x = val + incr
392 try:
393 x = int(x)
394 except OverflowError:
395 pass
396 self.test_one(x)
397
398 # Some error cases.
399 for direction in "<>":
400 for code in self.formatpair:
401 for badobject in "a string", 3+42j, randrange:
402 self.assertRaises((struct.error, TypeError),
403 struct.pack, direction + code,
404 badobject)
405
406 for args in [("bB", 1),
407 ("hH", 2),
408 ("iI", 4),
409 ("lL", 4),
410 ("qQ", 8)]:
411 t = IntTester(*args)
412 t.run()
413
414 def test_p_code(self):
415 # Test p ("Pascal string") code.
416 for code, input, expected, expectedback in [
417 ('p','abc', '\x00', ''),
418 ('1p', 'abc', '\x00', ''),
419 ('2p', 'abc', '\x01a', 'a'),
420 ('3p', 'abc', '\x02ab', 'ab'),
421 ('4p', 'abc', '\x03abc', 'abc'),
422 ('5p', 'abc', '\x03abc\x00', 'abc'),
423 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
424 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
425 got = struct.pack(code, input)
426 self.assertEqual(got, expected)
427 (got,) = struct.unpack(code, got)
428 self.assertEqual(got, expectedback)
429
430 def test_705836(self):
431 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
432 # from the low-order discarded bits could propagate into the exponent
433 # field, causing the result to be wrong by a factor of 2.
434 import math
435
436 for base in range(1, 33):
437 # smaller <- largest representable float less than base.
438 delta = 0.5
439 while base - delta / 2.0 != base:
440 delta /= 2.0
441 smaller = base - delta
442 # Packing this rounds away a solid string of trailing 1 bits.
443 packed = struct.pack("<f", smaller)
444 unpacked = struct.unpack("<f", packed)[0]
445 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
446 # 16, respectively.
447 self.assertEqual(base, unpacked)
448 bigpacked = struct.pack(">f", smaller)
449 self.assertEqual(bigpacked, string_reverse(packed))
450 unpacked = struct.unpack(">f", bigpacked)[0]
451 self.assertEqual(base, unpacked)
452
453 # Largest finite IEEE single.
454 big = (1 << 24) - 1
455 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000456 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000457 unpacked = struct.unpack(">f", packed)[0]
458 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000459
Benjamin Petersond5299862008-06-11 01:31:28 +0000460 # The same, but tack on a 1 bit so it rounds up to infinity.
461 big = (1 << 25) - 1
462 big = math.ldexp(big, 127 - 24)
463 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000464
Benjamin Petersond5299862008-06-11 01:31:28 +0000465 if PY_STRUCT_RANGE_CHECKING:
466 def test_1229380(self):
467 # SF bug 1229380. No struct.pack exception for some out of
468 # range integers
469 import sys
470 for endian in ('', '>', '<'):
471 for cls in (int, long):
472 for fmt in ('B', 'H', 'I', 'L'):
473 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000474
Benjamin Petersond5299862008-06-11 01:31:28 +0000475 deprecated_err(struct.pack, endian + 'B', cls(300))
476 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000477
Benjamin Petersond5299862008-06-11 01:31:28 +0000478 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
479 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000480
Benjamin Petersond5299862008-06-11 01:31:28 +0000481 def XXXtest_1530559(self):
482 # XXX This is broken: see the bug report
483 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
484 for endian in ('', '>', '<'):
485 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
486 self.check_float_coerce(endian + fmt, 1.0)
487 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000488
Georg Brandl47fe9812009-01-01 15:46:10 +0000489 def test_issue4228(self):
490 # Packing a long may yield either 32 or 64 bits
491 x = struct.pack('L', -1)[:4]
492 self.assertEqual(x, '\xff'*4)
493
Benjamin Petersond5299862008-06-11 01:31:28 +0000494 def test_unpack_from(self):
495 test_string = 'abcd01234'
496 fmt = '4s'
497 s = struct.Struct(fmt)
498 for cls in (str, buffer):
499 data = cls(test_string)
500 self.assertEqual(s.unpack_from(data), ('abcd',))
501 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
502 self.assertEqual(s.unpack_from(data, 4), ('0123',))
503 for i in xrange(6):
504 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
505 for i in xrange(6, len(test_string) + 1):
506 self.assertRaises(struct.error, s.unpack_from, data, i)
507 for cls in (str, buffer):
508 data = cls(test_string)
509 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
510 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
511 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
512 for i in xrange(6):
513 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
514 for i in xrange(6, len(test_string) + 1):
515 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000516
Benjamin Petersond5299862008-06-11 01:31:28 +0000517 def test_pack_into(self):
518 test_string = 'Reykjavik rocks, eow!'
519 writable_buf = array.array('c', ' '*100)
520 fmt = '21s'
521 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000522
Benjamin Petersond5299862008-06-11 01:31:28 +0000523 # Test without offset
524 s.pack_into(writable_buf, 0, test_string)
525 from_buf = writable_buf.tostring()[:len(test_string)]
526 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000527
Benjamin Petersond5299862008-06-11 01:31:28 +0000528 # Test with offset.
529 s.pack_into(writable_buf, 10, test_string)
530 from_buf = writable_buf.tostring()[:len(test_string)+10]
531 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000532
Benjamin Petersond5299862008-06-11 01:31:28 +0000533 # Go beyond boundaries.
534 small_buf = array.array('c', ' '*10)
535 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
536 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000537
Georg Brandl40e15ed2009-04-05 21:48:06 +0000538 # Test bogus offset (issue 3694)
539 sb = small_buf
540 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
541
Benjamin Petersond5299862008-06-11 01:31:28 +0000542 def test_pack_into_fn(self):
543 test_string = 'Reykjavik rocks, eow!'
544 writable_buf = array.array('c', ' '*100)
545 fmt = '21s'
546 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000547
Benjamin Petersond5299862008-06-11 01:31:28 +0000548 # Test without offset.
549 pack_into(writable_buf, 0, test_string)
550 from_buf = writable_buf.tostring()[:len(test_string)]
551 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000552
Benjamin Petersond5299862008-06-11 01:31:28 +0000553 # Test with offset.
554 pack_into(writable_buf, 10, test_string)
555 from_buf = writable_buf.tostring()[:len(test_string)+10]
556 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000557
Benjamin Petersond5299862008-06-11 01:31:28 +0000558 # Go beyond boundaries.
559 small_buf = array.array('c', ' '*10)
560 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
561 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000562
Benjamin Petersond5299862008-06-11 01:31:28 +0000563 def test_unpack_with_buffer(self):
564 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
565 data1 = array.array('B', '\x12\x34\x56\x78')
566 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
567 for data in [data1, data2]:
568 value, = struct.unpack('>I', data)
569 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000570
Benjamin Petersond5299862008-06-11 01:31:28 +0000571 def test_bool(self):
572 for prefix in tuple("<>!=")+('',):
573 false = (), [], [], '', 0
574 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000575
Benjamin Petersond5299862008-06-11 01:31:28 +0000576 falseFormat = prefix + '?' * len(false)
577 packedFalse = struct.pack(falseFormat, *false)
578 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000579
Benjamin Petersond5299862008-06-11 01:31:28 +0000580 trueFormat = prefix + '?' * len(true)
581 packedTrue = struct.pack(trueFormat, *true)
582 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000583
Benjamin Petersond5299862008-06-11 01:31:28 +0000584 self.assertEqual(len(true), len(unpackedTrue))
585 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000586
Benjamin Petersond5299862008-06-11 01:31:28 +0000587 for t in unpackedFalse:
588 self.assertFalse(t)
589 for t in unpackedTrue:
590 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000591
Benjamin Petersond5299862008-06-11 01:31:28 +0000592 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000593
Benjamin Petersond5299862008-06-11 01:31:28 +0000594 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000595
Benjamin Petersond5299862008-06-11 01:31:28 +0000596 if len(packed) != 1:
597 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
598 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000599
Benjamin Petersond5299862008-06-11 01:31:28 +0000600 for c in '\x01\x7f\xff\x0f\xf0':
601 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000602
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000603 if IS32BIT:
604 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000605 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000606
Mark Dickinson38b4a892010-06-12 08:49:42 +0000607 def test_count_overflow(self):
608 hugecount = '{0}b'.format(sys.maxsize+1)
609 self.assertRaises(struct.error, struct.calcsize, hugecount)
Gregory P. Smith9d534572008-06-11 07:41:16 +0000610
Mark Dickinson38b4a892010-06-12 08:49:42 +0000611 hugecount2 = '{0}b{1}H'.format(sys.maxsize//2, sys.maxsize//2)
612 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000613
Benjamin Petersond5299862008-06-11 01:31:28 +0000614def test_main():
615 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000616
Benjamin Petersond5299862008-06-11 01:31:28 +0000617if __name__ == '__main__':
618 test_main()