blob: c0b5e7c69c65ff8f80d7aa1f69f1799f6c2103a3 [file] [log] [blame]
Ezio Melotti90a732c2010-08-03 06:13:35 +00001import os
Martin Blais2856e5f2006-05-26 12:03:27 +00002import array
Benjamin Petersond5299862008-06-11 01:31:28 +00003import unittest
4import struct
Mark Dickinsone9a5a542010-04-06 15:19:40 +00005import inspect
Ezio Melotti90a732c2010-08-03 06:13:35 +00006import warnings
7from test.test_support import run_unittest, check_warnings, _check_py3k_warnings
8
Barry Warsaw07a0eec1996-12-12 23:34:06 +00009
Benjamin Petersond5299862008-06-11 01:31:28 +000010from functools import wraps
Brett Cannon672237d2008-09-09 00:49:16 +000011from test.test_support import TestFailed, verbose, run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +000012
Tim Peters17e17d42001-06-13 22:45:27 +000013import sys
14ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000015IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000016
Ezio Melotti90a732c2010-08-03 06:13:35 +000017testmod_filename = os.path.splitext(__file__)[0] + '.py'
Bob Ippolito2fd39772006-05-29 22:55:48 +000018try:
19 import _struct
20except ImportError:
21 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000022 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000023 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000024else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000025 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
26 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
27 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000028
Tim Peters17e17d42001-06-13 22:45:27 +000029def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000030 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000031
32def bigendian_to_native(value):
33 if ISBIGENDIAN:
34 return value
35 else:
36 return string_reverse(value)
37
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000038def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000039 @wraps(func)
40 def decorator(*args, **kw):
Brett Cannon672237d2008-09-09 00:49:16 +000041 with warnings.catch_warnings():
Nick Coghlan38469e22008-07-13 12:23:47 +000042 # We need this function to warn every time, so stick an
43 # unqualifed 'always' at the head of the filter list
44 warnings.simplefilter("always")
Benjamin Petersond5299862008-06-11 01:31:28 +000045 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000046 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000047 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000048
Benjamin Petersond5299862008-06-11 01:31:28 +000049@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000050def deprecated_err(func, *args):
51 try:
52 func(*args)
53 except (struct.error, TypeError):
54 pass
55 except DeprecationWarning:
56 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlan38469e22008-07-13 12:23:47 +000057 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000058 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000059 else:
60 raise TestFailed, "%s%s did not raise error" % (
61 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000062
Tim Peters17e17d42001-06-13 22:45:27 +000063
Benjamin Petersond5299862008-06-11 01:31:28 +000064class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000065
Benjamin Petersond5299862008-06-11 01:31:28 +000066 @with_warning_restore
67 def check_float_coerce(self, format, number):
68 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
69 if PY_STRUCT_FLOAT_COERCE == 2:
70 # Test for pre-2.5 struct module
Ezio Melotti90a732c2010-08-03 06:13:35 +000071 with check_warnings((".*integer argument expected, got float",
72 DeprecationWarning)) as w:
73 packed = struct.pack(format, number)
74 floored = struct.unpack(format, packed)[0]
Benjamin Petersond5299862008-06-11 01:31:28 +000075 self.assertEqual(floored, int(number),
76 "did not correcly coerce float to int")
77 return
78 try:
79 struct.pack(format, number)
80 except (struct.error, TypeError):
81 if PY_STRUCT_FLOAT_COERCE:
82 self.fail("expected DeprecationWarning for float coerce")
83 except DeprecationWarning:
84 if not PY_STRUCT_FLOAT_COERCE:
85 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000086 else:
Benjamin Petersond5299862008-06-11 01:31:28 +000087 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Benjamin Petersond5299862008-06-11 01:31:28 +000089 def test_isbigendian(self):
90 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000091
Benjamin Petersond5299862008-06-11 01:31:28 +000092 def test_consistence(self):
93 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000094
Benjamin Petersond5299862008-06-11 01:31:28 +000095 sz = struct.calcsize('i')
96 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000097
Benjamin Petersond5299862008-06-11 01:31:28 +000098 fmt = 'cbxxxxxxhhhhiillffd?'
99 fmt3 = '3c3b18x12h6i6l6f3d3?'
100 sz = struct.calcsize(fmt)
101 sz3 = struct.calcsize(fmt3)
102 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000103
Benjamin Petersond5299862008-06-11 01:31:28 +0000104 self.assertRaises(struct.error, struct.pack, 'iii', 3)
105 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
106 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
107 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
108 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
109 s = struct.pack('ii', 1, 2)
110 self.assertRaises(struct.error, struct.unpack, 'iii', s)
111 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000112
Mark Dickinsone9a5a542010-04-06 15:19:40 +0000113 def test_warnings_stacklevel(self):
114 # Python versions between 2.6 and 2.6.5 were producing
115 # warning messages at the wrong stacklevel.
116 def inner(fn, *args):
117 return inspect.currentframe().f_lineno, fn(*args)
118
119 def check_warning_stacklevel(fn, *args):
120 with warnings.catch_warnings(record=True) as w:
121 # "always" to make sure __warningregistry__ isn't affected
122 warnings.simplefilter("always")
123 lineno, result = inner(fn, *args)
124 for warn in w:
125 self.assertEqual(warn.lineno, lineno)
126
127 # out of range warnings
128 check_warning_stacklevel(struct.pack, '<L', -1)
129 check_warning_stacklevel(struct.pack, 'L', -1)
130 check_warning_stacklevel(struct.pack, '<h', 65536)
131 check_warning_stacklevel(struct.pack, '<l', 2**100)
132
133 # float warnings
134 check_warning_stacklevel(struct.pack, 'L', 3.1)
135
Benjamin Petersond5299862008-06-11 01:31:28 +0000136 def test_transitiveness(self):
137 c = 'a'
138 b = 1
139 h = 255
140 i = 65535
141 l = 65536
142 f = 3.1415
143 d = 3.1415
144 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000145
Benjamin Petersond5299862008-06-11 01:31:28 +0000146 for prefix in ('', '@', '<', '>', '=', '!'):
147 for format in ('xcbhilfd?', 'xcBHILfd?'):
148 format = prefix + format
149 s = struct.pack(format, c, b, h, i, l, f, d, t)
150 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
151 self.assertEqual(cp, c)
152 self.assertEqual(bp, b)
153 self.assertEqual(hp, h)
154 self.assertEqual(ip, i)
155 self.assertEqual(lp, l)
156 self.assertEqual(int(100 * fp), int(100 * f))
157 self.assertEqual(int(100 * dp), int(100 * d))
158 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000159
Benjamin Petersond5299862008-06-11 01:31:28 +0000160 def test_new_features(self):
161 # Test some of the new features in detail
162 # (format, argument, big-endian result, little-endian result, asymmetric)
163 tests = [
164 ('c', 'a', 'a', 'a', 0),
165 ('xc', 'a', '\0a', '\0a', 0),
166 ('cx', 'a', 'a\0', 'a\0', 0),
167 ('s', 'a', 'a', 'a', 0),
168 ('0s', 'helloworld', '', '', 1),
169 ('1s', 'helloworld', 'h', 'h', 1),
170 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
171 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
172 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
173 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
174 ('b', 7, '\7', '\7', 0),
175 ('b', -7, '\371', '\371', 0),
176 ('B', 7, '\7', '\7', 0),
177 ('B', 249, '\371', '\371', 0),
178 ('h', 700, '\002\274', '\274\002', 0),
179 ('h', -700, '\375D', 'D\375', 0),
180 ('H', 700, '\002\274', '\274\002', 0),
181 ('H', 0x10000-700, '\375D', 'D\375', 0),
182 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
183 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
184 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
185 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
186 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
187 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
188 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
189 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
190 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
191 ('d', 2.0, '@\000\000\000\000\000\000\000',
192 '\000\000\000\000\000\000\000@', 0),
193 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
194 ('d', -2.0, '\300\000\000\000\000\000\000\000',
195 '\000\000\000\000\000\000\000\300', 0),
196 ('?', 0, '\0', '\0', 0),
197 ('?', 3, '\1', '\1', 1),
198 ('?', True, '\1', '\1', 0),
199 ('?', [], '\0', '\0', 1),
200 ('?', (1,), '\1', '\1', 1),
201 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000202
Benjamin Petersond5299862008-06-11 01:31:28 +0000203 for fmt, arg, big, lil, asy in tests:
204 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
205 ('='+fmt, ISBIGENDIAN and big or lil)]:
206 res = struct.pack(xfmt, arg)
207 self.assertEqual(res, exp)
208 self.assertEqual(struct.calcsize(xfmt), len(res))
209 rev = struct.unpack(xfmt, res)[0]
210 if rev != arg:
211 self.assert_(asy)
212
213 def test_native_qQ(self):
214 # can't pack -1 as unsigned regardless
215 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
216 # can't pack string as 'q' regardless
217 self.assertRaises(struct.error, struct.pack, "q", "a")
218 # ditto, but 'Q'
219 self.assertRaises(struct.error, struct.pack, "Q", "a")
220
221 try:
222 struct.pack("q", 5)
223 except struct.error:
224 # does not have native q/Q
225 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000226 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000227 bytes = struct.calcsize('q')
228 # The expected values here are in big-endian format, primarily
229 # because I'm on a little-endian machine and so this is the
230 # clearest way (for me) to force the code to get exercised.
231 for format, input, expected in (
232 ('q', -1, '\xff' * bytes),
233 ('q', 0, '\x00' * bytes),
234 ('Q', 0, '\x00' * bytes),
235 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
236 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
237 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
238 got = struct.pack(format, input)
239 native_expected = bigendian_to_native(expected)
240 self.assertEqual(got, native_expected)
241 retrieved = struct.unpack(format, got)[0]
242 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000243
Benjamin Petersond5299862008-06-11 01:31:28 +0000244 def test_standard_integers(self):
245 # Standard integer tests (bBhHiIlLqQ).
246 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000247
Benjamin Petersond5299862008-06-11 01:31:28 +0000248 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000249
Benjamin Petersond5299862008-06-11 01:31:28 +0000250 # XXX Most std integer modes fail to test for out-of-range.
251 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
252 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
253 # reported by Mark Favas).
254 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000255
Benjamin Petersond5299862008-06-11 01:31:28 +0000256 def __init__(self, formatpair, bytesize):
257 self.assertEqual(len(formatpair), 2)
258 self.formatpair = formatpair
259 for direction in "<>!=":
260 for code in formatpair:
261 format = direction + code
262 self.assertEqual(struct.calcsize(format), bytesize)
263 self.bytesize = bytesize
264 self.bitsize = bytesize * 8
265 self.signed_code, self.unsigned_code = formatpair
266 self.unsigned_min = 0
267 self.unsigned_max = 2L**self.bitsize - 1
268 self.signed_min = -(2L**(self.bitsize-1))
269 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000270
Benjamin Petersond5299862008-06-11 01:31:28 +0000271 def test_one(self, x, pack=struct.pack,
272 unpack=struct.unpack,
273 unhexlify=binascii.unhexlify):
274 # Try signed.
275 code = self.signed_code
276 if self.signed_min <= x <= self.signed_max:
277 # Try big-endian.
278 expected = long(x)
279 if x < 0:
280 expected += 1L << self.bitsize
281 self.assert_(expected > 0)
282 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
283 if len(expected) & 1:
284 expected = "0" + expected
285 expected = unhexlify(expected)
286 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000287
Benjamin Petersond5299862008-06-11 01:31:28 +0000288 # Pack work?
289 format = ">" + code
290 got = pack(format, x)
291 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000292
Benjamin Petersond5299862008-06-11 01:31:28 +0000293 # Unpack work?
294 retrieved = unpack(format, got)[0]
295 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000296
Benjamin Petersond5299862008-06-11 01:31:28 +0000297 # Adding any byte should cause a "too big" error.
298 self.assertRaises((struct.error, TypeError), unpack, format,
299 '\x01' + got)
300 # Try little-endian.
301 format = "<" + code
302 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000303
Benjamin Petersond5299862008-06-11 01:31:28 +0000304 # Pack work?
305 got = pack(format, x)
306 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000307
Benjamin Petersond5299862008-06-11 01:31:28 +0000308 # Unpack work?
309 retrieved = unpack(format, got)[0]
310 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000311
Benjamin Petersond5299862008-06-11 01:31:28 +0000312 # Adding any byte should cause a "too big" error.
313 self.assertRaises((struct.error, TypeError), unpack, format,
314 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000315
Benjamin Petersond5299862008-06-11 01:31:28 +0000316 else:
317 # x is out of range -- verify pack realizes that.
318 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
319 if verbose:
320 print "Skipping buggy range check for code", code
321 else:
322 deprecated_err(pack, ">" + code, x)
323 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000324
Benjamin Petersond5299862008-06-11 01:31:28 +0000325 # Much the same for unsigned.
326 code = self.unsigned_code
327 if self.unsigned_min <= x <= self.unsigned_max:
328 # Try big-endian.
329 format = ">" + code
330 expected = long(x)
331 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
332 if len(expected) & 1:
333 expected = "0" + expected
334 expected = unhexlify(expected)
335 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000336
Benjamin Petersond5299862008-06-11 01:31:28 +0000337 # Pack work?
338 got = pack(format, x)
339 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000340
Benjamin Petersond5299862008-06-11 01:31:28 +0000341 # Unpack work?
342 retrieved = unpack(format, got)[0]
343 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000344
Benjamin Petersond5299862008-06-11 01:31:28 +0000345 # Adding any byte should cause a "too big" error.
346 self.assertRaises((struct.error, TypeError), unpack, format,
347 '\x01' + got)
348
349 # Try little-endian.
350 format = "<" + code
351 expected = string_reverse(expected)
352
353 # Pack work?
354 got = pack(format, x)
355 self.assertEqual(got, expected)
356
357 # Unpack work?
358 retrieved = unpack(format, got)[0]
359 self.assertEqual(x, retrieved)
360
361 # Adding any byte should cause a "too big" error.
362 self.assertRaises((struct.error, TypeError), unpack, format,
363 '\x01' + got)
364
365 else:
366 # x is out of range -- verify pack realizes that.
367 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
368 if verbose:
369 print "Skipping buggy range check for code", code
370 else:
371 deprecated_err(pack, ">" + code, x)
372 deprecated_err(pack, "<" + code, x)
373
374 def run(self):
375 from random import randrange
376
377 # Create all interesting powers of 2.
378 values = []
379 for exp in range(self.bitsize + 3):
380 values.append(1L << exp)
381
382 # Add some random values.
383 for i in range(self.bitsize):
384 val = 0L
385 for j in range(self.bytesize):
386 val = (val << 8) | randrange(256)
387 values.append(val)
388
389 # Try all those, and their negations, and +-1 from them. Note
390 # that this tests all power-of-2 boundaries in range, and a few out
391 # of range, plus +-(2**n +- 1).
392 for base in values:
393 for val in -base, base:
394 for incr in -1, 0, 1:
395 x = val + incr
396 try:
397 x = int(x)
398 except OverflowError:
399 pass
400 self.test_one(x)
401
402 # Some error cases.
403 for direction in "<>":
404 for code in self.formatpair:
405 for badobject in "a string", 3+42j, randrange:
406 self.assertRaises((struct.error, TypeError),
407 struct.pack, direction + code,
408 badobject)
409
410 for args in [("bB", 1),
411 ("hH", 2),
412 ("iI", 4),
413 ("lL", 4),
414 ("qQ", 8)]:
415 t = IntTester(*args)
416 t.run()
417
418 def test_p_code(self):
419 # Test p ("Pascal string") code.
420 for code, input, expected, expectedback in [
421 ('p','abc', '\x00', ''),
422 ('1p', 'abc', '\x00', ''),
423 ('2p', 'abc', '\x01a', 'a'),
424 ('3p', 'abc', '\x02ab', 'ab'),
425 ('4p', 'abc', '\x03abc', 'abc'),
426 ('5p', 'abc', '\x03abc\x00', 'abc'),
427 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
428 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
429 got = struct.pack(code, input)
430 self.assertEqual(got, expected)
431 (got,) = struct.unpack(code, got)
432 self.assertEqual(got, expectedback)
433
434 def test_705836(self):
435 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
436 # from the low-order discarded bits could propagate into the exponent
437 # field, causing the result to be wrong by a factor of 2.
438 import math
439
440 for base in range(1, 33):
441 # smaller <- largest representable float less than base.
442 delta = 0.5
443 while base - delta / 2.0 != base:
444 delta /= 2.0
445 smaller = base - delta
446 # Packing this rounds away a solid string of trailing 1 bits.
447 packed = struct.pack("<f", smaller)
448 unpacked = struct.unpack("<f", packed)[0]
449 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
450 # 16, respectively.
451 self.assertEqual(base, unpacked)
452 bigpacked = struct.pack(">f", smaller)
453 self.assertEqual(bigpacked, string_reverse(packed))
454 unpacked = struct.unpack(">f", bigpacked)[0]
455 self.assertEqual(base, unpacked)
456
457 # Largest finite IEEE single.
458 big = (1 << 24) - 1
459 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000460 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000461 unpacked = struct.unpack(">f", packed)[0]
462 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000463
Benjamin Petersond5299862008-06-11 01:31:28 +0000464 # The same, but tack on a 1 bit so it rounds up to infinity.
465 big = (1 << 25) - 1
466 big = math.ldexp(big, 127 - 24)
467 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000468
Benjamin Petersond5299862008-06-11 01:31:28 +0000469 if PY_STRUCT_RANGE_CHECKING:
470 def test_1229380(self):
471 # SF bug 1229380. No struct.pack exception for some out of
472 # range integers
473 import sys
474 for endian in ('', '>', '<'):
475 for cls in (int, long):
476 for fmt in ('B', 'H', 'I', 'L'):
477 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000478
Benjamin Petersond5299862008-06-11 01:31:28 +0000479 deprecated_err(struct.pack, endian + 'B', cls(300))
480 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000481
Benjamin Petersond5299862008-06-11 01:31:28 +0000482 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
483 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000484
Benjamin Petersond5299862008-06-11 01:31:28 +0000485 def XXXtest_1530559(self):
486 # XXX This is broken: see the bug report
487 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
488 for endian in ('', '>', '<'):
489 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
490 self.check_float_coerce(endian + fmt, 1.0)
491 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000492
Georg Brandl47fe9812009-01-01 15:46:10 +0000493 def test_issue4228(self):
494 # Packing a long may yield either 32 or 64 bits
Ezio Melotti90a732c2010-08-03 06:13:35 +0000495 with _check_py3k_warnings(("struct integer overflow masking is deprecated",
496 DeprecationWarning)):
497 x = struct.pack('L', -1)[:4]
Georg Brandl47fe9812009-01-01 15:46:10 +0000498 self.assertEqual(x, '\xff'*4)
499
Ezio Melotti90a732c2010-08-03 06:13:35 +0000500 def test_unpack_from(self, cls=str):
501 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000502 fmt = '4s'
503 s = struct.Struct(fmt)
Ezio Melotti90a732c2010-08-03 06:13:35 +0000504
505 self.assertEqual(s.unpack_from(data), ('abcd',))
506 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
507 for i in xrange(6):
508 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
509 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
510 for i in xrange(6, len(data) + 1):
511 self.assertRaises(struct.error, s.unpack_from, data, i)
512 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000513
Benjamin Petersond5299862008-06-11 01:31:28 +0000514 def test_pack_into(self):
515 test_string = 'Reykjavik rocks, eow!'
516 writable_buf = array.array('c', ' '*100)
517 fmt = '21s'
518 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000519
Benjamin Petersond5299862008-06-11 01:31:28 +0000520 # Test without offset
521 s.pack_into(writable_buf, 0, test_string)
522 from_buf = writable_buf.tostring()[:len(test_string)]
523 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000524
Benjamin Petersond5299862008-06-11 01:31:28 +0000525 # Test with offset.
526 s.pack_into(writable_buf, 10, test_string)
527 from_buf = writable_buf.tostring()[:len(test_string)+10]
528 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000529
Benjamin Petersond5299862008-06-11 01:31:28 +0000530 # Go beyond boundaries.
531 small_buf = array.array('c', ' '*10)
532 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
533 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000534
Georg Brandl40e15ed2009-04-05 21:48:06 +0000535 # Test bogus offset (issue 3694)
536 sb = small_buf
537 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
538
Benjamin Petersond5299862008-06-11 01:31:28 +0000539 def test_pack_into_fn(self):
540 test_string = 'Reykjavik rocks, eow!'
541 writable_buf = array.array('c', ' '*100)
542 fmt = '21s'
543 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000544
Benjamin Petersond5299862008-06-11 01:31:28 +0000545 # Test without offset.
546 pack_into(writable_buf, 0, test_string)
547 from_buf = writable_buf.tostring()[:len(test_string)]
548 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000549
Benjamin Petersond5299862008-06-11 01:31:28 +0000550 # Test with offset.
551 pack_into(writable_buf, 10, test_string)
552 from_buf = writable_buf.tostring()[:len(test_string)+10]
553 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000554
Benjamin Petersond5299862008-06-11 01:31:28 +0000555 # Go beyond boundaries.
556 small_buf = array.array('c', ' '*10)
557 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
558 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000559
Benjamin Petersond5299862008-06-11 01:31:28 +0000560 def test_unpack_with_buffer(self):
Ezio Melotti90a732c2010-08-03 06:13:35 +0000561 with _check_py3k_warnings(("buffer.. not supported in 3.x",
562 DeprecationWarning)):
563 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
564 data1 = array.array('B', '\x12\x34\x56\x78')
565 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
566 for data in [data1, data2]:
567 value, = struct.unpack('>I', data)
568 self.assertEqual(value, 0x12345678)
569
570 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000571
Benjamin Petersond5299862008-06-11 01:31:28 +0000572 def test_bool(self):
573 for prefix in tuple("<>!=")+('',):
574 false = (), [], [], '', 0
Ezio Melotti90a732c2010-08-03 06:13:35 +0000575 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000576
Benjamin Petersond5299862008-06-11 01:31:28 +0000577 falseFormat = prefix + '?' * len(false)
578 packedFalse = struct.pack(falseFormat, *false)
579 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000580
Benjamin Petersond5299862008-06-11 01:31:28 +0000581 trueFormat = prefix + '?' * len(true)
582 packedTrue = struct.pack(trueFormat, *true)
583 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000584
Benjamin Petersond5299862008-06-11 01:31:28 +0000585 self.assertEqual(len(true), len(unpackedTrue))
586 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000587
Benjamin Petersond5299862008-06-11 01:31:28 +0000588 for t in unpackedFalse:
589 self.assertFalse(t)
590 for t in unpackedTrue:
591 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000592
Benjamin Petersond5299862008-06-11 01:31:28 +0000593 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000594
Benjamin Petersond5299862008-06-11 01:31:28 +0000595 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000596
Benjamin Petersond5299862008-06-11 01:31:28 +0000597 if len(packed) != 1:
598 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
599 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000600
Benjamin Petersond5299862008-06-11 01:31:28 +0000601 for c in '\x01\x7f\xff\x0f\xf0':
602 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000603
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000604 if IS32BIT:
605 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000606 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000607
Mark Dickinson38b4a892010-06-12 08:49:42 +0000608 def test_count_overflow(self):
609 hugecount = '{0}b'.format(sys.maxsize+1)
610 self.assertRaises(struct.error, struct.calcsize, hugecount)
Gregory P. Smith9d534572008-06-11 07:41:16 +0000611
Mark Dickinson38b4a892010-06-12 08:49:42 +0000612 hugecount2 = '{0}b{1}H'.format(sys.maxsize//2, sys.maxsize//2)
613 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000614
Benjamin Petersond5299862008-06-11 01:31:28 +0000615def test_main():
616 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000617
Benjamin Petersond5299862008-06-11 01:31:28 +0000618if __name__ == '__main__':
619 test_main()