blob: ad754df51ac3274ce0aca32495a6a640c728b020 [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 +000015del sys
Tim Peters17e17d42001-06-13 22:45:27 +000016
Bob Ippolito2fd39772006-05-29 22:55:48 +000017try:
18 import _struct
19except ImportError:
20 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000021 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000022 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000023else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000024 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
25 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
26 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000027
Tim Peters17e17d42001-06-13 22:45:27 +000028def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000029 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000030
31def bigendian_to_native(value):
32 if ISBIGENDIAN:
33 return value
34 else:
35 return string_reverse(value)
36
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000037def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000038 @wraps(func)
39 def decorator(*args, **kw):
Brett Cannon672237d2008-09-09 00:49:16 +000040 with warnings.catch_warnings():
Nick Coghlan38469e22008-07-13 12:23:47 +000041 # We need this function to warn every time, so stick an
42 # unqualifed 'always' at the head of the filter list
43 warnings.simplefilter("always")
Benjamin Petersond5299862008-06-11 01:31:28 +000044 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000045 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000046 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000047
Benjamin Petersond5299862008-06-11 01:31:28 +000048@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +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:
Nick Coghlan38469e22008-07-13 12:23:47 +000056 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000057 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000058 else:
59 raise TestFailed, "%s%s did not raise error" % (
60 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000061
Tim Peters17e17d42001-06-13 22:45:27 +000062
Benjamin Petersond5299862008-06-11 01:31:28 +000063class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000064
Benjamin Petersond5299862008-06-11 01:31:28 +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:
Benjamin Petersond5299862008-06-11 01:31:28 +000084 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000085
Benjamin Petersond5299862008-06-11 01:31:28 +000086 def test_isbigendian(self):
87 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Benjamin Petersond5299862008-06-11 01:31:28 +000089 def test_consistence(self):
90 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000091
Benjamin Petersond5299862008-06-11 01:31:28 +000092 sz = struct.calcsize('i')
93 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000094
Benjamin Petersond5299862008-06-11 01:31:28 +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
Benjamin Petersond5299862008-06-11 01:31:28 +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', '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
Mark Dickinsone9a5a542010-04-06 15:19:40 +0000110 def test_warnings_stacklevel(self):
111 # Python versions between 2.6 and 2.6.5 were producing
112 # warning messages at the wrong stacklevel.
113 def inner(fn, *args):
114 return inspect.currentframe().f_lineno, fn(*args)
115
116 def check_warning_stacklevel(fn, *args):
117 with warnings.catch_warnings(record=True) as w:
118 # "always" to make sure __warningregistry__ isn't affected
119 warnings.simplefilter("always")
120 lineno, result = inner(fn, *args)
121 for warn in w:
122 self.assertEqual(warn.lineno, lineno)
123
124 # out of range warnings
125 check_warning_stacklevel(struct.pack, '<L', -1)
126 check_warning_stacklevel(struct.pack, 'L', -1)
127 check_warning_stacklevel(struct.pack, '<h', 65536)
128 check_warning_stacklevel(struct.pack, '<l', 2**100)
129
130 # float warnings
131 check_warning_stacklevel(struct.pack, 'L', 3.1)
132
Benjamin Petersond5299862008-06-11 01:31:28 +0000133 def test_transitiveness(self):
134 c = 'a'
135 b = 1
136 h = 255
137 i = 65535
138 l = 65536
139 f = 3.1415
140 d = 3.1415
141 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000142
Benjamin Petersond5299862008-06-11 01:31:28 +0000143 for prefix in ('', '@', '<', '>', '=', '!'):
144 for format in ('xcbhilfd?', 'xcBHILfd?'):
145 format = prefix + format
146 s = struct.pack(format, c, b, h, i, l, f, d, t)
147 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
148 self.assertEqual(cp, c)
149 self.assertEqual(bp, b)
150 self.assertEqual(hp, h)
151 self.assertEqual(ip, i)
152 self.assertEqual(lp, l)
153 self.assertEqual(int(100 * fp), int(100 * f))
154 self.assertEqual(int(100 * dp), int(100 * d))
155 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000156
Benjamin Petersond5299862008-06-11 01:31:28 +0000157 def test_new_features(self):
158 # Test some of the new features in detail
159 # (format, argument, big-endian result, little-endian result, asymmetric)
160 tests = [
161 ('c', 'a', 'a', 'a', 0),
162 ('xc', 'a', '\0a', '\0a', 0),
163 ('cx', 'a', 'a\0', 'a\0', 0),
164 ('s', 'a', 'a', 'a', 0),
165 ('0s', 'helloworld', '', '', 1),
166 ('1s', 'helloworld', 'h', 'h', 1),
167 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
168 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
169 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
170 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
171 ('b', 7, '\7', '\7', 0),
172 ('b', -7, '\371', '\371', 0),
173 ('B', 7, '\7', '\7', 0),
174 ('B', 249, '\371', '\371', 0),
175 ('h', 700, '\002\274', '\274\002', 0),
176 ('h', -700, '\375D', 'D\375', 0),
177 ('H', 700, '\002\274', '\274\002', 0),
178 ('H', 0x10000-700, '\375D', 'D\375', 0),
179 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
180 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
181 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
182 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
183 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
184 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
185 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
186 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
187 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
188 ('d', 2.0, '@\000\000\000\000\000\000\000',
189 '\000\000\000\000\000\000\000@', 0),
190 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
191 ('d', -2.0, '\300\000\000\000\000\000\000\000',
192 '\000\000\000\000\000\000\000\300', 0),
193 ('?', 0, '\0', '\0', 0),
194 ('?', 3, '\1', '\1', 1),
195 ('?', True, '\1', '\1', 0),
196 ('?', [], '\0', '\0', 1),
197 ('?', (1,), '\1', '\1', 1),
198 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000199
Benjamin Petersond5299862008-06-11 01:31:28 +0000200 for fmt, arg, big, lil, asy in tests:
201 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
202 ('='+fmt, ISBIGENDIAN and big or lil)]:
203 res = struct.pack(xfmt, arg)
204 self.assertEqual(res, exp)
205 self.assertEqual(struct.calcsize(xfmt), len(res))
206 rev = struct.unpack(xfmt, res)[0]
207 if rev != arg:
208 self.assert_(asy)
209
210 def test_native_qQ(self):
211 # can't pack -1 as unsigned regardless
212 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
213 # can't pack string as 'q' regardless
214 self.assertRaises(struct.error, struct.pack, "q", "a")
215 # ditto, but 'Q'
216 self.assertRaises(struct.error, struct.pack, "Q", "a")
217
218 try:
219 struct.pack("q", 5)
220 except struct.error:
221 # does not have native q/Q
222 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000223 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000224 bytes = struct.calcsize('q')
225 # The expected values here are in big-endian format, primarily
226 # because I'm on a little-endian machine and so this is the
227 # clearest way (for me) to force the code to get exercised.
228 for format, input, expected in (
229 ('q', -1, '\xff' * bytes),
230 ('q', 0, '\x00' * bytes),
231 ('Q', 0, '\x00' * bytes),
232 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
233 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
234 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
235 got = struct.pack(format, input)
236 native_expected = bigendian_to_native(expected)
237 self.assertEqual(got, native_expected)
238 retrieved = struct.unpack(format, got)[0]
239 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000240
Benjamin Petersond5299862008-06-11 01:31:28 +0000241 def test_standard_integers(self):
242 # Standard integer tests (bBhHiIlLqQ).
243 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000244
Benjamin Petersond5299862008-06-11 01:31:28 +0000245 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000246
Benjamin Petersond5299862008-06-11 01:31:28 +0000247 # XXX Most std integer modes fail to test for out-of-range.
248 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
249 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
250 # reported by Mark Favas).
251 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000252
Benjamin Petersond5299862008-06-11 01:31:28 +0000253 def __init__(self, formatpair, bytesize):
254 self.assertEqual(len(formatpair), 2)
255 self.formatpair = formatpair
256 for direction in "<>!=":
257 for code in formatpair:
258 format = direction + code
259 self.assertEqual(struct.calcsize(format), bytesize)
260 self.bytesize = bytesize
261 self.bitsize = bytesize * 8
262 self.signed_code, self.unsigned_code = formatpair
263 self.unsigned_min = 0
264 self.unsigned_max = 2L**self.bitsize - 1
265 self.signed_min = -(2L**(self.bitsize-1))
266 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000267
Benjamin Petersond5299862008-06-11 01:31:28 +0000268 def test_one(self, x, pack=struct.pack,
269 unpack=struct.unpack,
270 unhexlify=binascii.unhexlify):
271 # Try signed.
272 code = self.signed_code
273 if self.signed_min <= x <= self.signed_max:
274 # Try big-endian.
275 expected = long(x)
276 if x < 0:
277 expected += 1L << self.bitsize
278 self.assert_(expected > 0)
279 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
280 if len(expected) & 1:
281 expected = "0" + expected
282 expected = unhexlify(expected)
283 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000284
Benjamin Petersond5299862008-06-11 01:31:28 +0000285 # Pack work?
286 format = ">" + code
287 got = pack(format, x)
288 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000289
Benjamin Petersond5299862008-06-11 01:31:28 +0000290 # Unpack work?
291 retrieved = unpack(format, got)[0]
292 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000293
Benjamin Petersond5299862008-06-11 01:31:28 +0000294 # Adding any byte should cause a "too big" error.
295 self.assertRaises((struct.error, TypeError), unpack, format,
296 '\x01' + got)
297 # Try little-endian.
298 format = "<" + code
299 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000300
Benjamin Petersond5299862008-06-11 01:31:28 +0000301 # Pack work?
302 got = pack(format, x)
303 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000304
Benjamin Petersond5299862008-06-11 01:31:28 +0000305 # Unpack work?
306 retrieved = unpack(format, got)[0]
307 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000308
Benjamin Petersond5299862008-06-11 01:31:28 +0000309 # Adding any byte should cause a "too big" error.
310 self.assertRaises((struct.error, TypeError), unpack, format,
311 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000312
Benjamin Petersond5299862008-06-11 01:31:28 +0000313 else:
314 # x is out of range -- verify pack realizes that.
315 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
316 if verbose:
317 print "Skipping buggy range check for code", code
318 else:
319 deprecated_err(pack, ">" + code, x)
320 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000321
Benjamin Petersond5299862008-06-11 01:31:28 +0000322 # Much the same for unsigned.
323 code = self.unsigned_code
324 if self.unsigned_min <= x <= self.unsigned_max:
325 # Try big-endian.
326 format = ">" + code
327 expected = long(x)
328 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
329 if len(expected) & 1:
330 expected = "0" + expected
331 expected = unhexlify(expected)
332 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000333
Benjamin Petersond5299862008-06-11 01:31:28 +0000334 # Pack work?
335 got = pack(format, x)
336 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000337
Benjamin Petersond5299862008-06-11 01:31:28 +0000338 # Unpack work?
339 retrieved = unpack(format, got)[0]
340 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000341
Benjamin Petersond5299862008-06-11 01:31:28 +0000342 # Adding any byte should cause a "too big" error.
343 self.assertRaises((struct.error, TypeError), unpack, format,
344 '\x01' + got)
345
346 # Try little-endian.
347 format = "<" + code
348 expected = string_reverse(expected)
349
350 # Pack work?
351 got = pack(format, x)
352 self.assertEqual(got, expected)
353
354 # Unpack work?
355 retrieved = unpack(format, got)[0]
356 self.assertEqual(x, retrieved)
357
358 # Adding any byte should cause a "too big" error.
359 self.assertRaises((struct.error, TypeError), unpack, format,
360 '\x01' + got)
361
362 else:
363 # x is out of range -- verify pack realizes that.
364 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
365 if verbose:
366 print "Skipping buggy range check for code", code
367 else:
368 deprecated_err(pack, ">" + code, x)
369 deprecated_err(pack, "<" + code, x)
370
371 def run(self):
372 from random import randrange
373
374 # Create all interesting powers of 2.
375 values = []
376 for exp in range(self.bitsize + 3):
377 values.append(1L << exp)
378
379 # Add some random values.
380 for i in range(self.bitsize):
381 val = 0L
382 for j in range(self.bytesize):
383 val = (val << 8) | randrange(256)
384 values.append(val)
385
386 # Try all those, and their negations, and +-1 from them. Note
387 # that this tests all power-of-2 boundaries in range, and a few out
388 # of range, plus +-(2**n +- 1).
389 for base in values:
390 for val in -base, base:
391 for incr in -1, 0, 1:
392 x = val + incr
393 try:
394 x = int(x)
395 except OverflowError:
396 pass
397 self.test_one(x)
398
399 # Some error cases.
400 for direction in "<>":
401 for code in self.formatpair:
402 for badobject in "a string", 3+42j, randrange:
403 self.assertRaises((struct.error, TypeError),
404 struct.pack, direction + code,
405 badobject)
406
407 for args in [("bB", 1),
408 ("hH", 2),
409 ("iI", 4),
410 ("lL", 4),
411 ("qQ", 8)]:
412 t = IntTester(*args)
413 t.run()
414
415 def test_p_code(self):
416 # Test p ("Pascal string") code.
417 for code, input, expected, expectedback in [
418 ('p','abc', '\x00', ''),
419 ('1p', 'abc', '\x00', ''),
420 ('2p', 'abc', '\x01a', 'a'),
421 ('3p', 'abc', '\x02ab', 'ab'),
422 ('4p', 'abc', '\x03abc', 'abc'),
423 ('5p', 'abc', '\x03abc\x00', 'abc'),
424 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
425 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
426 got = struct.pack(code, input)
427 self.assertEqual(got, expected)
428 (got,) = struct.unpack(code, got)
429 self.assertEqual(got, expectedback)
430
431 def test_705836(self):
432 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
433 # from the low-order discarded bits could propagate into the exponent
434 # field, causing the result to be wrong by a factor of 2.
435 import math
436
437 for base in range(1, 33):
438 # smaller <- largest representable float less than base.
439 delta = 0.5
440 while base - delta / 2.0 != base:
441 delta /= 2.0
442 smaller = base - delta
443 # Packing this rounds away a solid string of trailing 1 bits.
444 packed = struct.pack("<f", smaller)
445 unpacked = struct.unpack("<f", packed)[0]
446 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
447 # 16, respectively.
448 self.assertEqual(base, unpacked)
449 bigpacked = struct.pack(">f", smaller)
450 self.assertEqual(bigpacked, string_reverse(packed))
451 unpacked = struct.unpack(">f", bigpacked)[0]
452 self.assertEqual(base, unpacked)
453
454 # Largest finite IEEE single.
455 big = (1 << 24) - 1
456 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000457 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000458 unpacked = struct.unpack(">f", packed)[0]
459 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000460
Benjamin Petersond5299862008-06-11 01:31:28 +0000461 # The same, but tack on a 1 bit so it rounds up to infinity.
462 big = (1 << 25) - 1
463 big = math.ldexp(big, 127 - 24)
464 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000465
Benjamin Petersond5299862008-06-11 01:31:28 +0000466 if PY_STRUCT_RANGE_CHECKING:
467 def test_1229380(self):
468 # SF bug 1229380. No struct.pack exception for some out of
469 # range integers
470 import sys
471 for endian in ('', '>', '<'):
472 for cls in (int, long):
473 for fmt in ('B', 'H', 'I', 'L'):
474 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000475
Benjamin Petersond5299862008-06-11 01:31:28 +0000476 deprecated_err(struct.pack, endian + 'B', cls(300))
477 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000478
Benjamin Petersond5299862008-06-11 01:31:28 +0000479 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
480 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000481
Benjamin Petersond5299862008-06-11 01:31:28 +0000482 def XXXtest_1530559(self):
483 # XXX This is broken: see the bug report
484 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
485 for endian in ('', '>', '<'):
486 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
487 self.check_float_coerce(endian + fmt, 1.0)
488 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000489
Georg Brandl47fe9812009-01-01 15:46:10 +0000490 def test_issue4228(self):
491 # Packing a long may yield either 32 or 64 bits
492 x = struct.pack('L', -1)[:4]
493 self.assertEqual(x, '\xff'*4)
494
Benjamin Petersond5299862008-06-11 01:31:28 +0000495 def test_unpack_from(self):
496 test_string = 'abcd01234'
497 fmt = '4s'
498 s = struct.Struct(fmt)
499 for cls in (str, buffer):
500 data = cls(test_string)
501 self.assertEqual(s.unpack_from(data), ('abcd',))
502 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
503 self.assertEqual(s.unpack_from(data, 4), ('0123',))
504 for i in xrange(6):
505 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
506 for i in xrange(6, len(test_string) + 1):
507 self.assertRaises(struct.error, s.unpack_from, data, i)
508 for cls in (str, buffer):
509 data = cls(test_string)
510 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
511 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
512 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
513 for i in xrange(6):
514 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
515 for i in xrange(6, len(test_string) + 1):
516 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000517
Benjamin Petersond5299862008-06-11 01:31:28 +0000518 def test_pack_into(self):
519 test_string = 'Reykjavik rocks, eow!'
520 writable_buf = array.array('c', ' '*100)
521 fmt = '21s'
522 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000523
Benjamin Petersond5299862008-06-11 01:31:28 +0000524 # Test without offset
525 s.pack_into(writable_buf, 0, test_string)
526 from_buf = writable_buf.tostring()[:len(test_string)]
527 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000528
Benjamin Petersond5299862008-06-11 01:31:28 +0000529 # Test with offset.
530 s.pack_into(writable_buf, 10, test_string)
531 from_buf = writable_buf.tostring()[:len(test_string)+10]
532 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000533
Benjamin Petersond5299862008-06-11 01:31:28 +0000534 # Go beyond boundaries.
535 small_buf = array.array('c', ' '*10)
536 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
537 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000538
Georg Brandl40e15ed2009-04-05 21:48:06 +0000539 # Test bogus offset (issue 3694)
540 sb = small_buf
541 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
542
Benjamin Petersond5299862008-06-11 01:31:28 +0000543 def test_pack_into_fn(self):
544 test_string = 'Reykjavik rocks, eow!'
545 writable_buf = array.array('c', ' '*100)
546 fmt = '21s'
547 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000548
Benjamin Petersond5299862008-06-11 01:31:28 +0000549 # Test without offset.
550 pack_into(writable_buf, 0, test_string)
551 from_buf = writable_buf.tostring()[:len(test_string)]
552 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000553
Benjamin Petersond5299862008-06-11 01:31:28 +0000554 # Test with offset.
555 pack_into(writable_buf, 10, test_string)
556 from_buf = writable_buf.tostring()[:len(test_string)+10]
557 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000558
Benjamin Petersond5299862008-06-11 01:31:28 +0000559 # Go beyond boundaries.
560 small_buf = array.array('c', ' '*10)
561 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
562 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000563
Benjamin Petersond5299862008-06-11 01:31:28 +0000564 def test_unpack_with_buffer(self):
565 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
566 data1 = array.array('B', '\x12\x34\x56\x78')
567 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
568 for data in [data1, data2]:
569 value, = struct.unpack('>I', data)
570 self.assertEqual(value, 0x12345678)
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
575 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
608
Tim Petersf733abb2007-01-30 03:03:46 +0000609
Benjamin Petersond5299862008-06-11 01:31:28 +0000610def test_main():
611 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000612
Benjamin Petersond5299862008-06-11 01:31:28 +0000613if __name__ == '__main__':
614 test_main()