blob: 6e35db85dccda4c8dff357951730a47413dffd99 [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):
230 self.assertEqual(len(formatpair), 2)
231 self.formatpair = formatpair
232 for direction in "<>!=":
233 for code in formatpair:
234 format = direction + code
235 self.assertEqual(struct.calcsize(format), bytesize)
236 self.bytesize = bytesize
237 self.bitsize = bytesize * 8
238 self.signed_code, self.unsigned_code = formatpair
239 self.unsigned_min = 0
240 self.unsigned_max = 2L**self.bitsize - 1
241 self.signed_min = -(2L**(self.bitsize-1))
242 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000243
Benjamin Petersond5299862008-06-11 01:31:28 +0000244 def test_one(self, x, pack=struct.pack,
245 unpack=struct.unpack,
246 unhexlify=binascii.unhexlify):
247 # Try signed.
248 code = self.signed_code
249 if self.signed_min <= x <= self.signed_max:
250 # Try big-endian.
251 expected = long(x)
252 if x < 0:
253 expected += 1L << self.bitsize
254 self.assert_(expected > 0)
255 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
256 if len(expected) & 1:
257 expected = "0" + expected
258 expected = unhexlify(expected)
259 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000260
Benjamin Petersond5299862008-06-11 01:31:28 +0000261 # Pack work?
262 format = ">" + code
263 got = pack(format, x)
264 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000265
Benjamin Petersond5299862008-06-11 01:31:28 +0000266 # Unpack work?
267 retrieved = unpack(format, got)[0]
268 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000269
Benjamin Petersond5299862008-06-11 01:31:28 +0000270 # Adding any byte should cause a "too big" error.
271 self.assertRaises((struct.error, TypeError), unpack, format,
272 '\x01' + got)
273 # Try little-endian.
274 format = "<" + code
275 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000276
Benjamin Petersond5299862008-06-11 01:31:28 +0000277 # Pack work?
278 got = pack(format, x)
279 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000280
Benjamin Petersond5299862008-06-11 01:31:28 +0000281 # Unpack work?
282 retrieved = unpack(format, got)[0]
283 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000284
Benjamin Petersond5299862008-06-11 01:31:28 +0000285 # Adding any byte should cause a "too big" error.
286 self.assertRaises((struct.error, TypeError), unpack, format,
287 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000288
Benjamin Petersond5299862008-06-11 01:31:28 +0000289 else:
290 # x is out of range -- verify pack realizes that.
291 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
292 if verbose:
293 print "Skipping buggy range check for code", code
294 else:
295 deprecated_err(pack, ">" + code, x)
296 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000297
Benjamin Petersond5299862008-06-11 01:31:28 +0000298 # Much the same for unsigned.
299 code = self.unsigned_code
300 if self.unsigned_min <= x <= self.unsigned_max:
301 # Try big-endian.
302 format = ">" + code
303 expected = long(x)
304 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
305 if len(expected) & 1:
306 expected = "0" + expected
307 expected = unhexlify(expected)
308 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000309
Benjamin Petersond5299862008-06-11 01:31:28 +0000310 # Pack work?
311 got = pack(format, x)
312 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000313
Benjamin Petersond5299862008-06-11 01:31:28 +0000314 # Unpack work?
315 retrieved = unpack(format, got)[0]
316 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000317
Benjamin Petersond5299862008-06-11 01:31:28 +0000318 # Adding any byte should cause a "too big" error.
319 self.assertRaises((struct.error, TypeError), unpack, format,
320 '\x01' + got)
321
322 # Try little-endian.
323 format = "<" + code
324 expected = string_reverse(expected)
325
326 # Pack work?
327 got = pack(format, x)
328 self.assertEqual(got, expected)
329
330 # Unpack work?
331 retrieved = unpack(format, got)[0]
332 self.assertEqual(x, retrieved)
333
334 # Adding any byte should cause a "too big" error.
335 self.assertRaises((struct.error, TypeError), unpack, format,
336 '\x01' + got)
337
338 else:
339 # x is out of range -- verify pack realizes that.
340 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
341 if verbose:
342 print "Skipping buggy range check for code", code
343 else:
344 deprecated_err(pack, ">" + code, x)
345 deprecated_err(pack, "<" + code, x)
346
347 def run(self):
348 from random import randrange
349
350 # Create all interesting powers of 2.
351 values = []
352 for exp in range(self.bitsize + 3):
353 values.append(1L << exp)
354
355 # Add some random values.
356 for i in range(self.bitsize):
357 val = 0L
358 for j in range(self.bytesize):
359 val = (val << 8) | randrange(256)
360 values.append(val)
361
362 # Try all those, and their negations, and +-1 from them. Note
363 # that this tests all power-of-2 boundaries in range, and a few out
364 # of range, plus +-(2**n +- 1).
365 for base in values:
366 for val in -base, base:
367 for incr in -1, 0, 1:
368 x = val + incr
369 try:
370 x = int(x)
371 except OverflowError:
372 pass
373 self.test_one(x)
374
375 # Some error cases.
376 for direction in "<>":
377 for code in self.formatpair:
378 for badobject in "a string", 3+42j, randrange:
379 self.assertRaises((struct.error, TypeError),
380 struct.pack, direction + code,
381 badobject)
382
383 for args in [("bB", 1),
384 ("hH", 2),
385 ("iI", 4),
386 ("lL", 4),
387 ("qQ", 8)]:
388 t = IntTester(*args)
389 t.run()
390
391 def test_p_code(self):
392 # Test p ("Pascal string") code.
393 for code, input, expected, expectedback in [
394 ('p','abc', '\x00', ''),
395 ('1p', 'abc', '\x00', ''),
396 ('2p', 'abc', '\x01a', 'a'),
397 ('3p', 'abc', '\x02ab', 'ab'),
398 ('4p', 'abc', '\x03abc', 'abc'),
399 ('5p', 'abc', '\x03abc\x00', 'abc'),
400 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
401 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
402 got = struct.pack(code, input)
403 self.assertEqual(got, expected)
404 (got,) = struct.unpack(code, got)
405 self.assertEqual(got, expectedback)
406
407 def test_705836(self):
408 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
409 # from the low-order discarded bits could propagate into the exponent
410 # field, causing the result to be wrong by a factor of 2.
411 import math
412
413 for base in range(1, 33):
414 # smaller <- largest representable float less than base.
415 delta = 0.5
416 while base - delta / 2.0 != base:
417 delta /= 2.0
418 smaller = base - delta
419 # Packing this rounds away a solid string of trailing 1 bits.
420 packed = struct.pack("<f", smaller)
421 unpacked = struct.unpack("<f", packed)[0]
422 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
423 # 16, respectively.
424 self.assertEqual(base, unpacked)
425 bigpacked = struct.pack(">f", smaller)
426 self.assertEqual(bigpacked, string_reverse(packed))
427 unpacked = struct.unpack(">f", bigpacked)[0]
428 self.assertEqual(base, unpacked)
429
430 # Largest finite IEEE single.
431 big = (1 << 24) - 1
432 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000433 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000434 unpacked = struct.unpack(">f", packed)[0]
435 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000436
Benjamin Petersond5299862008-06-11 01:31:28 +0000437 # The same, but tack on a 1 bit so it rounds up to infinity.
438 big = (1 << 25) - 1
439 big = math.ldexp(big, 127 - 24)
440 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000441
Benjamin Petersond5299862008-06-11 01:31:28 +0000442 if PY_STRUCT_RANGE_CHECKING:
443 def test_1229380(self):
444 # SF bug 1229380. No struct.pack exception for some out of
445 # range integers
446 import sys
447 for endian in ('', '>', '<'):
448 for cls in (int, long):
449 for fmt in ('B', 'H', 'I', 'L'):
450 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000451
Benjamin Petersond5299862008-06-11 01:31:28 +0000452 deprecated_err(struct.pack, endian + 'B', cls(300))
453 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000454
Benjamin Petersond5299862008-06-11 01:31:28 +0000455 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
456 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000457
Benjamin Petersond5299862008-06-11 01:31:28 +0000458 def XXXtest_1530559(self):
459 # XXX This is broken: see the bug report
460 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
461 for endian in ('', '>', '<'):
462 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
463 self.check_float_coerce(endian + fmt, 1.0)
464 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000465
Georg Brandl6269fec2009-01-01 12:15:31 +0000466 def test_issue4228(self):
467 # Packing a long may yield either 32 or 64 bits
468 x = struct.pack('L', -1)[:4]
469 self.assertEqual(x, '\xff'*4)
470
Benjamin Petersond5299862008-06-11 01:31:28 +0000471 def test_unpack_from(self):
472 test_string = 'abcd01234'
473 fmt = '4s'
474 s = struct.Struct(fmt)
475 for cls in (str, buffer):
476 data = cls(test_string)
477 self.assertEqual(s.unpack_from(data), ('abcd',))
478 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
479 self.assertEqual(s.unpack_from(data, 4), ('0123',))
480 for i in xrange(6):
481 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
482 for i in xrange(6, len(test_string) + 1):
483 self.assertRaises(struct.error, s.unpack_from, data, i)
484 for cls in (str, buffer):
485 data = cls(test_string)
486 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
487 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
488 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
489 for i in xrange(6):
490 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
491 for i in xrange(6, len(test_string) + 1):
492 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000493
Benjamin Petersond5299862008-06-11 01:31:28 +0000494 def test_pack_into(self):
495 test_string = 'Reykjavik rocks, eow!'
496 writable_buf = array.array('c', ' '*100)
497 fmt = '21s'
498 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000499
Benjamin Petersond5299862008-06-11 01:31:28 +0000500 # Test without offset
501 s.pack_into(writable_buf, 0, test_string)
502 from_buf = writable_buf.tostring()[:len(test_string)]
503 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000504
Benjamin Petersond5299862008-06-11 01:31:28 +0000505 # Test with offset.
506 s.pack_into(writable_buf, 10, test_string)
507 from_buf = writable_buf.tostring()[:len(test_string)+10]
508 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000509
Benjamin Petersond5299862008-06-11 01:31:28 +0000510 # Go beyond boundaries.
511 small_buf = array.array('c', ' '*10)
512 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
513 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000514
Georg Brandl0638a082009-02-13 11:03:59 +0000515 # Test bogus offset (issue 3694)
516 sb = small_buf
517 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
518
Benjamin Petersond5299862008-06-11 01:31:28 +0000519 def test_pack_into_fn(self):
520 test_string = 'Reykjavik rocks, eow!'
521 writable_buf = array.array('c', ' '*100)
522 fmt = '21s'
523 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000524
Benjamin Petersond5299862008-06-11 01:31:28 +0000525 # Test without offset.
526 pack_into(writable_buf, 0, test_string)
527 from_buf = writable_buf.tostring()[:len(test_string)]
528 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000529
Benjamin Petersond5299862008-06-11 01:31:28 +0000530 # Test with offset.
531 pack_into(writable_buf, 10, test_string)
532 from_buf = writable_buf.tostring()[:len(test_string)+10]
533 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000534
Benjamin Petersond5299862008-06-11 01:31:28 +0000535 # Go beyond boundaries.
536 small_buf = array.array('c', ' '*10)
537 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
538 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000539
Benjamin Petersond5299862008-06-11 01:31:28 +0000540 def test_unpack_with_buffer(self):
541 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
542 data1 = array.array('B', '\x12\x34\x56\x78')
543 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
544 for data in [data1, data2]:
545 value, = struct.unpack('>I', data)
546 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000547
Benjamin Petersond5299862008-06-11 01:31:28 +0000548 def test_bool(self):
549 for prefix in tuple("<>!=")+('',):
550 false = (), [], [], '', 0
551 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000552
Benjamin Petersond5299862008-06-11 01:31:28 +0000553 falseFormat = prefix + '?' * len(false)
554 packedFalse = struct.pack(falseFormat, *false)
555 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000556
Benjamin Petersond5299862008-06-11 01:31:28 +0000557 trueFormat = prefix + '?' * len(true)
558 packedTrue = struct.pack(trueFormat, *true)
559 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000560
Benjamin Petersond5299862008-06-11 01:31:28 +0000561 self.assertEqual(len(true), len(unpackedTrue))
562 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000563
Benjamin Petersond5299862008-06-11 01:31:28 +0000564 for t in unpackedFalse:
565 self.assertFalse(t)
566 for t in unpackedTrue:
567 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000568
Benjamin Petersond5299862008-06-11 01:31:28 +0000569 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000570
Benjamin Petersond5299862008-06-11 01:31:28 +0000571 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000572
Benjamin Petersond5299862008-06-11 01:31:28 +0000573 if len(packed) != 1:
574 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
575 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000576
Benjamin Petersond5299862008-06-11 01:31:28 +0000577 for c in '\x01\x7f\xff\x0f\xf0':
578 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000579
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000580 if IS32BIT:
581 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000582 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000583
584
Tim Petersf733abb2007-01-30 03:03:46 +0000585
Benjamin Petersond5299862008-06-11 01:31:28 +0000586def test_main():
587 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000588
Benjamin Petersond5299862008-06-11 01:31:28 +0000589if __name__ == '__main__':
590 test_main()