blob: 1cf3484fa59f57b1dbfd55d742dac9edad1e7beb [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
Georg Brandl6269fec2009-01-01 12:15:31 +00005warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
6 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00007
Benjamin Petersond5299862008-06-11 01:31:28 +00008from functools import wraps
Brett Cannon672237d2008-09-09 00:49:16 +00009from test.test_support import TestFailed, verbose, run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +000010
Tim Peters17e17d42001-06-13 22:45:27 +000011import sys
12ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000013IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000014del sys
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)
Mark Dickinson4015f622009-02-10 15:46:50 +000051 except (struct.error, OverflowError):
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000052 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
Benjamin Petersond5299862008-06-11 01:31:28 +0000109 def test_transitiveness(self):
110 c = 'a'
111 b = 1
112 h = 255
113 i = 65535
114 l = 65536
115 f = 3.1415
116 d = 3.1415
117 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000118
Benjamin Petersond5299862008-06-11 01:31:28 +0000119 for prefix in ('', '@', '<', '>', '=', '!'):
120 for format in ('xcbhilfd?', 'xcBHILfd?'):
121 format = prefix + format
122 s = struct.pack(format, c, b, h, i, l, f, d, t)
123 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
124 self.assertEqual(cp, c)
125 self.assertEqual(bp, b)
126 self.assertEqual(hp, h)
127 self.assertEqual(ip, i)
128 self.assertEqual(lp, l)
129 self.assertEqual(int(100 * fp), int(100 * f))
130 self.assertEqual(int(100 * dp), int(100 * d))
131 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000132
Benjamin Petersond5299862008-06-11 01:31:28 +0000133 def test_new_features(self):
134 # Test some of the new features in detail
135 # (format, argument, big-endian result, little-endian result, asymmetric)
136 tests = [
137 ('c', 'a', 'a', 'a', 0),
138 ('xc', 'a', '\0a', '\0a', 0),
139 ('cx', 'a', 'a\0', 'a\0', 0),
140 ('s', 'a', 'a', 'a', 0),
141 ('0s', 'helloworld', '', '', 1),
142 ('1s', 'helloworld', 'h', 'h', 1),
143 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
144 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
145 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
146 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
147 ('b', 7, '\7', '\7', 0),
148 ('b', -7, '\371', '\371', 0),
149 ('B', 7, '\7', '\7', 0),
150 ('B', 249, '\371', '\371', 0),
151 ('h', 700, '\002\274', '\274\002', 0),
152 ('h', -700, '\375D', 'D\375', 0),
153 ('H', 700, '\002\274', '\274\002', 0),
154 ('H', 0x10000-700, '\375D', 'D\375', 0),
155 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
156 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
158 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
159 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
160 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
161 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
162 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
163 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
164 ('d', 2.0, '@\000\000\000\000\000\000\000',
165 '\000\000\000\000\000\000\000@', 0),
166 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
167 ('d', -2.0, '\300\000\000\000\000\000\000\000',
168 '\000\000\000\000\000\000\000\300', 0),
169 ('?', 0, '\0', '\0', 0),
170 ('?', 3, '\1', '\1', 1),
171 ('?', True, '\1', '\1', 0),
172 ('?', [], '\0', '\0', 1),
173 ('?', (1,), '\1', '\1', 1),
174 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000175
Benjamin Petersond5299862008-06-11 01:31:28 +0000176 for fmt, arg, big, lil, asy in tests:
177 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
178 ('='+fmt, ISBIGENDIAN and big or lil)]:
179 res = struct.pack(xfmt, arg)
180 self.assertEqual(res, exp)
181 self.assertEqual(struct.calcsize(xfmt), len(res))
182 rev = struct.unpack(xfmt, res)[0]
183 if rev != arg:
184 self.assert_(asy)
185
186 def test_native_qQ(self):
187 # can't pack -1 as unsigned regardless
Mark Dickinson4015f622009-02-10 15:46:50 +0000188 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Benjamin Petersond5299862008-06-11 01:31:28 +0000189 # can't pack string as 'q' regardless
190 self.assertRaises(struct.error, struct.pack, "q", "a")
191 # ditto, but 'Q'
192 self.assertRaises(struct.error, struct.pack, "Q", "a")
193
194 try:
195 struct.pack("q", 5)
196 except struct.error:
197 # does not have native q/Q
198 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000199 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000200 bytes = struct.calcsize('q')
201 # The expected values here are in big-endian format, primarily
202 # because I'm on a little-endian machine and so this is the
203 # clearest way (for me) to force the code to get exercised.
204 for format, input, expected in (
205 ('q', -1, '\xff' * bytes),
206 ('q', 0, '\x00' * bytes),
207 ('Q', 0, '\x00' * bytes),
208 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
209 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
210 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
211 got = struct.pack(format, input)
212 native_expected = bigendian_to_native(expected)
213 self.assertEqual(got, native_expected)
214 retrieved = struct.unpack(format, got)[0]
215 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000216
Benjamin Petersond5299862008-06-11 01:31:28 +0000217 def test_standard_integers(self):
218 # Standard integer tests (bBhHiIlLqQ).
219 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000220
Benjamin Petersond5299862008-06-11 01:31:28 +0000221 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000222
Benjamin Petersond5299862008-06-11 01:31:28 +0000223 # XXX Most std integer modes fail to test for out-of-range.
224 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
225 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
226 # reported by Mark Favas).
227 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000228
Benjamin Petersond5299862008-06-11 01:31:28 +0000229 def __init__(self, formatpair, bytesize):
Gregory P. Smith28399852009-03-31 16:54:10 +0000230 super(IntTester, self).__init__(methodName='test_one')
Benjamin Petersond5299862008-06-11 01:31:28 +0000231 self.assertEqual(len(formatpair), 2)
232 self.formatpair = formatpair
233 for direction in "<>!=":
234 for code in formatpair:
235 format = direction + code
236 self.assertEqual(struct.calcsize(format), bytesize)
237 self.bytesize = bytesize
238 self.bitsize = bytesize * 8
239 self.signed_code, self.unsigned_code = formatpair
240 self.unsigned_min = 0
241 self.unsigned_max = 2L**self.bitsize - 1
242 self.signed_min = -(2L**(self.bitsize-1))
243 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000244
Benjamin Petersond5299862008-06-11 01:31:28 +0000245 def test_one(self, x, pack=struct.pack,
246 unpack=struct.unpack,
247 unhexlify=binascii.unhexlify):
248 # Try signed.
249 code = self.signed_code
250 if self.signed_min <= x <= self.signed_max:
251 # Try big-endian.
252 expected = long(x)
253 if x < 0:
254 expected += 1L << self.bitsize
255 self.assert_(expected > 0)
256 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
257 if len(expected) & 1:
258 expected = "0" + expected
259 expected = unhexlify(expected)
260 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000261
Benjamin Petersond5299862008-06-11 01:31:28 +0000262 # Pack work?
263 format = ">" + code
264 got = pack(format, x)
265 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000266
Benjamin Petersond5299862008-06-11 01:31:28 +0000267 # Unpack work?
268 retrieved = unpack(format, got)[0]
269 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000270
Benjamin Petersond5299862008-06-11 01:31:28 +0000271 # Adding any byte should cause a "too big" error.
272 self.assertRaises((struct.error, TypeError), unpack, format,
273 '\x01' + got)
274 # Try little-endian.
275 format = "<" + code
276 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000277
Benjamin Petersond5299862008-06-11 01:31:28 +0000278 # Pack work?
279 got = pack(format, x)
280 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000281
Benjamin Petersond5299862008-06-11 01:31:28 +0000282 # Unpack work?
283 retrieved = unpack(format, got)[0]
284 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000285
Benjamin Petersond5299862008-06-11 01:31:28 +0000286 # Adding any byte should cause a "too big" error.
287 self.assertRaises((struct.error, TypeError), unpack, format,
288 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000289
Benjamin Petersond5299862008-06-11 01:31:28 +0000290 else:
291 # x is out of range -- verify pack realizes that.
292 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
293 if verbose:
294 print "Skipping buggy range check for code", code
295 else:
296 deprecated_err(pack, ">" + code, x)
297 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000298
Benjamin Petersond5299862008-06-11 01:31:28 +0000299 # Much the same for unsigned.
300 code = self.unsigned_code
301 if self.unsigned_min <= x <= self.unsigned_max:
302 # Try big-endian.
303 format = ">" + code
304 expected = long(x)
305 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
306 if len(expected) & 1:
307 expected = "0" + expected
308 expected = unhexlify(expected)
309 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000310
Benjamin Petersond5299862008-06-11 01:31:28 +0000311 # Pack work?
312 got = pack(format, x)
313 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000314
Benjamin Petersond5299862008-06-11 01:31:28 +0000315 # Unpack work?
316 retrieved = unpack(format, got)[0]
317 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000318
Benjamin Petersond5299862008-06-11 01:31:28 +0000319 # Adding any byte should cause a "too big" error.
320 self.assertRaises((struct.error, TypeError), unpack, format,
321 '\x01' + got)
322
323 # Try little-endian.
324 format = "<" + code
325 expected = string_reverse(expected)
326
327 # Pack work?
328 got = pack(format, x)
329 self.assertEqual(got, expected)
330
331 # Unpack work?
332 retrieved = unpack(format, got)[0]
333 self.assertEqual(x, retrieved)
334
335 # Adding any byte should cause a "too big" error.
336 self.assertRaises((struct.error, TypeError), unpack, format,
337 '\x01' + got)
338
339 else:
340 # x is out of range -- verify pack realizes that.
341 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
342 if verbose:
343 print "Skipping buggy range check for code", code
344 else:
345 deprecated_err(pack, ">" + code, x)
346 deprecated_err(pack, "<" + code, x)
347
348 def run(self):
349 from random import randrange
350
351 # Create all interesting powers of 2.
352 values = []
353 for exp in range(self.bitsize + 3):
354 values.append(1L << exp)
355
356 # Add some random values.
357 for i in range(self.bitsize):
358 val = 0L
359 for j in range(self.bytesize):
360 val = (val << 8) | randrange(256)
361 values.append(val)
362
363 # Try all those, and their negations, and +-1 from them. Note
364 # that this tests all power-of-2 boundaries in range, and a few out
365 # of range, plus +-(2**n +- 1).
366 for base in values:
367 for val in -base, base:
368 for incr in -1, 0, 1:
369 x = val + incr
370 try:
371 x = int(x)
372 except OverflowError:
373 pass
374 self.test_one(x)
375
376 # Some error cases.
377 for direction in "<>":
378 for code in self.formatpair:
379 for badobject in "a string", 3+42j, randrange:
380 self.assertRaises((struct.error, TypeError),
381 struct.pack, direction + code,
382 badobject)
383
384 for args in [("bB", 1),
385 ("hH", 2),
386 ("iI", 4),
387 ("lL", 4),
388 ("qQ", 8)]:
389 t = IntTester(*args)
390 t.run()
391
392 def test_p_code(self):
393 # Test p ("Pascal string") code.
394 for code, input, expected, expectedback in [
395 ('p','abc', '\x00', ''),
396 ('1p', 'abc', '\x00', ''),
397 ('2p', 'abc', '\x01a', 'a'),
398 ('3p', 'abc', '\x02ab', 'ab'),
399 ('4p', 'abc', '\x03abc', 'abc'),
400 ('5p', 'abc', '\x03abc\x00', 'abc'),
401 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
402 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
403 got = struct.pack(code, input)
404 self.assertEqual(got, expected)
405 (got,) = struct.unpack(code, got)
406 self.assertEqual(got, expectedback)
407
408 def test_705836(self):
409 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
410 # from the low-order discarded bits could propagate into the exponent
411 # field, causing the result to be wrong by a factor of 2.
412 import math
413
414 for base in range(1, 33):
415 # smaller <- largest representable float less than base.
416 delta = 0.5
417 while base - delta / 2.0 != base:
418 delta /= 2.0
419 smaller = base - delta
420 # Packing this rounds away a solid string of trailing 1 bits.
421 packed = struct.pack("<f", smaller)
422 unpacked = struct.unpack("<f", packed)[0]
423 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
424 # 16, respectively.
425 self.assertEqual(base, unpacked)
426 bigpacked = struct.pack(">f", smaller)
427 self.assertEqual(bigpacked, string_reverse(packed))
428 unpacked = struct.unpack(">f", bigpacked)[0]
429 self.assertEqual(base, unpacked)
430
431 # Largest finite IEEE single.
432 big = (1 << 24) - 1
433 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000434 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000435 unpacked = struct.unpack(">f", packed)[0]
436 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000437
Benjamin Petersond5299862008-06-11 01:31:28 +0000438 # The same, but tack on a 1 bit so it rounds up to infinity.
439 big = (1 << 25) - 1
440 big = math.ldexp(big, 127 - 24)
441 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000442
Benjamin Petersond5299862008-06-11 01:31:28 +0000443 if PY_STRUCT_RANGE_CHECKING:
444 def test_1229380(self):
445 # SF bug 1229380. No struct.pack exception for some out of
446 # range integers
447 import sys
448 for endian in ('', '>', '<'):
449 for cls in (int, long):
450 for fmt in ('B', 'H', 'I', 'L'):
451 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000452
Benjamin Petersond5299862008-06-11 01:31:28 +0000453 deprecated_err(struct.pack, endian + 'B', cls(300))
454 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000455
Benjamin Petersond5299862008-06-11 01:31:28 +0000456 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
457 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000458
Benjamin Petersond5299862008-06-11 01:31:28 +0000459 def XXXtest_1530559(self):
460 # XXX This is broken: see the bug report
461 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
462 for endian in ('', '>', '<'):
463 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
464 self.check_float_coerce(endian + fmt, 1.0)
465 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000466
Georg Brandl6269fec2009-01-01 12:15:31 +0000467 def test_issue4228(self):
468 # Packing a long may yield either 32 or 64 bits
469 x = struct.pack('L', -1)[:4]
470 self.assertEqual(x, '\xff'*4)
471
Benjamin Petersond5299862008-06-11 01:31:28 +0000472 def test_unpack_from(self):
473 test_string = 'abcd01234'
474 fmt = '4s'
475 s = struct.Struct(fmt)
476 for cls in (str, buffer):
477 data = cls(test_string)
478 self.assertEqual(s.unpack_from(data), ('abcd',))
479 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
480 self.assertEqual(s.unpack_from(data, 4), ('0123',))
481 for i in xrange(6):
482 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
483 for i in xrange(6, len(test_string) + 1):
484 self.assertRaises(struct.error, s.unpack_from, data, i)
485 for cls in (str, buffer):
486 data = cls(test_string)
487 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
488 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
489 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
490 for i in xrange(6):
491 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
492 for i in xrange(6, len(test_string) + 1):
493 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000494
Benjamin Petersond5299862008-06-11 01:31:28 +0000495 def test_pack_into(self):
496 test_string = 'Reykjavik rocks, eow!'
497 writable_buf = array.array('c', ' '*100)
498 fmt = '21s'
499 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000500
Benjamin Petersond5299862008-06-11 01:31:28 +0000501 # Test without offset
502 s.pack_into(writable_buf, 0, test_string)
503 from_buf = writable_buf.tostring()[:len(test_string)]
504 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000505
Benjamin Petersond5299862008-06-11 01:31:28 +0000506 # Test with offset.
507 s.pack_into(writable_buf, 10, test_string)
508 from_buf = writable_buf.tostring()[:len(test_string)+10]
509 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000510
Benjamin Petersond5299862008-06-11 01:31:28 +0000511 # Go beyond boundaries.
512 small_buf = array.array('c', ' '*10)
513 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
514 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000515
Georg Brandl0638a082009-02-13 11:03:59 +0000516 # Test bogus offset (issue 3694)
517 sb = small_buf
518 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
519
Benjamin Petersond5299862008-06-11 01:31:28 +0000520 def test_pack_into_fn(self):
521 test_string = 'Reykjavik rocks, eow!'
522 writable_buf = array.array('c', ' '*100)
523 fmt = '21s'
524 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000525
Benjamin Petersond5299862008-06-11 01:31:28 +0000526 # Test without offset.
527 pack_into(writable_buf, 0, test_string)
528 from_buf = writable_buf.tostring()[:len(test_string)]
529 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000530
Benjamin Petersond5299862008-06-11 01:31:28 +0000531 # Test with offset.
532 pack_into(writable_buf, 10, test_string)
533 from_buf = writable_buf.tostring()[:len(test_string)+10]
534 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000535
Benjamin Petersond5299862008-06-11 01:31:28 +0000536 # Go beyond boundaries.
537 small_buf = array.array('c', ' '*10)
538 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
539 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000540
Benjamin Petersond5299862008-06-11 01:31:28 +0000541 def test_unpack_with_buffer(self):
542 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
543 data1 = array.array('B', '\x12\x34\x56\x78')
544 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
545 for data in [data1, data2]:
546 value, = struct.unpack('>I', data)
547 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000548
Benjamin Petersond5299862008-06-11 01:31:28 +0000549 def test_bool(self):
550 for prefix in tuple("<>!=")+('',):
551 false = (), [], [], '', 0
552 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000553
Benjamin Petersond5299862008-06-11 01:31:28 +0000554 falseFormat = prefix + '?' * len(false)
555 packedFalse = struct.pack(falseFormat, *false)
556 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000557
Benjamin Petersond5299862008-06-11 01:31:28 +0000558 trueFormat = prefix + '?' * len(true)
559 packedTrue = struct.pack(trueFormat, *true)
560 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000561
Benjamin Petersond5299862008-06-11 01:31:28 +0000562 self.assertEqual(len(true), len(unpackedTrue))
563 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000564
Benjamin Petersond5299862008-06-11 01:31:28 +0000565 for t in unpackedFalse:
566 self.assertFalse(t)
567 for t in unpackedTrue:
568 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000569
Benjamin Petersond5299862008-06-11 01:31:28 +0000570 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000571
Benjamin Petersond5299862008-06-11 01:31:28 +0000572 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000573
Benjamin Petersond5299862008-06-11 01:31:28 +0000574 if len(packed) != 1:
575 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
576 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000577
Benjamin Petersond5299862008-06-11 01:31:28 +0000578 for c in '\x01\x7f\xff\x0f\xf0':
579 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000580
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000581 if IS32BIT:
582 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000583 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000584
585
Tim Petersf733abb2007-01-30 03:03:46 +0000586
Benjamin Petersond5299862008-06-11 01:31:28 +0000587def test_main():
588 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000589
Benjamin Petersond5299862008-06-11 01:31:28 +0000590if __name__ == '__main__':
591 test_main()