blob: 7fd058b0728238d78f7c9180b2e7c0a1fd684ec9 [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
Barry Warsaw07a0eec1996-12-12 23:34:06 +00005
Benjamin Petersond5299862008-06-11 01:31:28 +00006from functools import wraps
7from test.test_support import TestFailed, verbose, run_unittest, catch_warning
8
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Gregory P. Smith9d534572008-06-11 07:41:16 +000011IS32BIT = sys.maxint == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000012del sys
Tim Peters17e17d42001-06-13 22:45:27 +000013
Bob Ippolito2fd39772006-05-29 22:55:48 +000014try:
15 import _struct
16except ImportError:
17 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000018 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000019 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000020else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000021 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
22 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
23 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000024
Tim Peters17e17d42001-06-13 22:45:27 +000025def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000026 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000027
28def bigendian_to_native(value):
29 if ISBIGENDIAN:
30 return value
31 else:
32 return string_reverse(value)
33
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000034def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000035 @wraps(func)
36 def decorator(*args, **kw):
37 with catch_warning():
Brett Cannon6d9520c2006-12-13 23:09:53 +000038 # Grrr, we need this function to warn every time. Without removing
39 # the warningregistry, running test_tarfile then test_struct would fail
40 # on 64-bit platforms.
41 globals = func.func_globals
42 if '__warningregistry__' in globals:
43 del globals['__warningregistry__']
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:
56 raise TestFailed, "%s%s expected to raise struct.error" % (
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
Benjamin Petersond5299862008-06-11 01:31:28 +0000110 def test_transitiveness(self):
111 c = 'a'
112 b = 1
113 h = 255
114 i = 65535
115 l = 65536
116 f = 3.1415
117 d = 3.1415
118 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000119
Benjamin Petersond5299862008-06-11 01:31:28 +0000120 for prefix in ('', '@', '<', '>', '=', '!'):
121 for format in ('xcbhilfd?', 'xcBHILfd?'):
122 format = prefix + format
123 s = struct.pack(format, c, b, h, i, l, f, d, t)
124 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
125 self.assertEqual(cp, c)
126 self.assertEqual(bp, b)
127 self.assertEqual(hp, h)
128 self.assertEqual(ip, i)
129 self.assertEqual(lp, l)
130 self.assertEqual(int(100 * fp), int(100 * f))
131 self.assertEqual(int(100 * dp), int(100 * d))
132 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000133
Benjamin Petersond5299862008-06-11 01:31:28 +0000134 def test_new_features(self):
135 # Test some of the new features in detail
136 # (format, argument, big-endian result, little-endian result, asymmetric)
137 tests = [
138 ('c', 'a', 'a', 'a', 0),
139 ('xc', 'a', '\0a', '\0a', 0),
140 ('cx', 'a', 'a\0', 'a\0', 0),
141 ('s', 'a', 'a', 'a', 0),
142 ('0s', 'helloworld', '', '', 1),
143 ('1s', 'helloworld', 'h', 'h', 1),
144 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
145 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
146 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
147 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
148 ('b', 7, '\7', '\7', 0),
149 ('b', -7, '\371', '\371', 0),
150 ('B', 7, '\7', '\7', 0),
151 ('B', 249, '\371', '\371', 0),
152 ('h', 700, '\002\274', '\274\002', 0),
153 ('h', -700, '\375D', 'D\375', 0),
154 ('H', 700, '\002\274', '\274\002', 0),
155 ('H', 0x10000-700, '\375D', 'D\375', 0),
156 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
157 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
158 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
159 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
160 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
161 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
162 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
163 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
164 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
165 ('d', 2.0, '@\000\000\000\000\000\000\000',
166 '\000\000\000\000\000\000\000@', 0),
167 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
168 ('d', -2.0, '\300\000\000\000\000\000\000\000',
169 '\000\000\000\000\000\000\000\300', 0),
170 ('?', 0, '\0', '\0', 0),
171 ('?', 3, '\1', '\1', 1),
172 ('?', True, '\1', '\1', 0),
173 ('?', [], '\0', '\0', 1),
174 ('?', (1,), '\1', '\1', 1),
175 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000176
Benjamin Petersond5299862008-06-11 01:31:28 +0000177 for fmt, arg, big, lil, asy in tests:
178 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
179 ('='+fmt, ISBIGENDIAN and big or lil)]:
180 res = struct.pack(xfmt, arg)
181 self.assertEqual(res, exp)
182 self.assertEqual(struct.calcsize(xfmt), len(res))
183 rev = struct.unpack(xfmt, res)[0]
184 if rev != arg:
185 self.assert_(asy)
186
187 def test_native_qQ(self):
188 # can't pack -1 as unsigned regardless
189 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
190 # can't pack string as 'q' regardless
191 self.assertRaises(struct.error, struct.pack, "q", "a")
192 # ditto, but 'Q'
193 self.assertRaises(struct.error, struct.pack, "Q", "a")
194
195 try:
196 struct.pack("q", 5)
197 except struct.error:
198 # does not have native q/Q
199 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000200 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000201 bytes = struct.calcsize('q')
202 # The expected values here are in big-endian format, primarily
203 # because I'm on a little-endian machine and so this is the
204 # clearest way (for me) to force the code to get exercised.
205 for format, input, expected in (
206 ('q', -1, '\xff' * bytes),
207 ('q', 0, '\x00' * bytes),
208 ('Q', 0, '\x00' * bytes),
209 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
210 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
211 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
212 got = struct.pack(format, input)
213 native_expected = bigendian_to_native(expected)
214 self.assertEqual(got, native_expected)
215 retrieved = struct.unpack(format, got)[0]
216 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000217
Benjamin Petersond5299862008-06-11 01:31:28 +0000218 def test_standard_integers(self):
219 # Standard integer tests (bBhHiIlLqQ).
220 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000221
Benjamin Petersond5299862008-06-11 01:31:28 +0000222 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000223
Benjamin Petersond5299862008-06-11 01:31:28 +0000224 # XXX Most std integer modes fail to test for out-of-range.
225 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
226 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
227 # reported by Mark Favas).
228 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000229
Benjamin Petersond5299862008-06-11 01:31:28 +0000230 def __init__(self, formatpair, bytesize):
231 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
Benjamin Petersond5299862008-06-11 01:31:28 +0000467 def test_unpack_from(self):
468 test_string = 'abcd01234'
469 fmt = '4s'
470 s = struct.Struct(fmt)
471 for cls in (str, buffer):
472 data = cls(test_string)
473 self.assertEqual(s.unpack_from(data), ('abcd',))
474 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
475 self.assertEqual(s.unpack_from(data, 4), ('0123',))
476 for i in xrange(6):
477 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
478 for i in xrange(6, len(test_string) + 1):
479 self.assertRaises(struct.error, s.unpack_from, data, i)
480 for cls in (str, buffer):
481 data = cls(test_string)
482 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
483 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
484 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
485 for i in xrange(6):
486 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
487 for i in xrange(6, len(test_string) + 1):
488 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000489
Benjamin Petersond5299862008-06-11 01:31:28 +0000490 def test_pack_into(self):
491 test_string = 'Reykjavik rocks, eow!'
492 writable_buf = array.array('c', ' '*100)
493 fmt = '21s'
494 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000495
Benjamin Petersond5299862008-06-11 01:31:28 +0000496 # Test without offset
497 s.pack_into(writable_buf, 0, test_string)
498 from_buf = writable_buf.tostring()[:len(test_string)]
499 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000500
Benjamin Petersond5299862008-06-11 01:31:28 +0000501 # Test with offset.
502 s.pack_into(writable_buf, 10, test_string)
503 from_buf = writable_buf.tostring()[:len(test_string)+10]
504 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000505
Benjamin Petersond5299862008-06-11 01:31:28 +0000506 # Go beyond boundaries.
507 small_buf = array.array('c', ' '*10)
508 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
509 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000510
Benjamin Petersond5299862008-06-11 01:31:28 +0000511 def test_pack_into_fn(self):
512 test_string = 'Reykjavik rocks, eow!'
513 writable_buf = array.array('c', ' '*100)
514 fmt = '21s'
515 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000516
Benjamin Petersond5299862008-06-11 01:31:28 +0000517 # Test without offset.
518 pack_into(writable_buf, 0, test_string)
519 from_buf = writable_buf.tostring()[:len(test_string)]
520 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000521
Benjamin Petersond5299862008-06-11 01:31:28 +0000522 # Test with offset.
523 pack_into(writable_buf, 10, test_string)
524 from_buf = writable_buf.tostring()[:len(test_string)+10]
525 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000526
Benjamin Petersond5299862008-06-11 01:31:28 +0000527 # Go beyond boundaries.
528 small_buf = array.array('c', ' '*10)
529 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
530 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000531
Benjamin Petersond5299862008-06-11 01:31:28 +0000532 def test_unpack_with_buffer(self):
533 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
534 data1 = array.array('B', '\x12\x34\x56\x78')
535 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
536 for data in [data1, data2]:
537 value, = struct.unpack('>I', data)
538 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000539
Benjamin Petersond5299862008-06-11 01:31:28 +0000540 def test_bool(self):
541 for prefix in tuple("<>!=")+('',):
542 false = (), [], [], '', 0
543 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000544
Benjamin Petersond5299862008-06-11 01:31:28 +0000545 falseFormat = prefix + '?' * len(false)
546 packedFalse = struct.pack(falseFormat, *false)
547 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000548
Benjamin Petersond5299862008-06-11 01:31:28 +0000549 trueFormat = prefix + '?' * len(true)
550 packedTrue = struct.pack(trueFormat, *true)
551 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000552
Benjamin Petersond5299862008-06-11 01:31:28 +0000553 self.assertEqual(len(true), len(unpackedTrue))
554 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000555
Benjamin Petersond5299862008-06-11 01:31:28 +0000556 for t in unpackedFalse:
557 self.assertFalse(t)
558 for t in unpackedTrue:
559 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000560
Benjamin Petersond5299862008-06-11 01:31:28 +0000561 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000562
Benjamin Petersond5299862008-06-11 01:31:28 +0000563 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000564
Benjamin Petersond5299862008-06-11 01:31:28 +0000565 if len(packed) != 1:
566 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
567 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000568
Benjamin Petersond5299862008-06-11 01:31:28 +0000569 for c in '\x01\x7f\xff\x0f\xf0':
570 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000571
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000572 if IS32BIT:
573 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000574 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000575
576
Tim Petersf733abb2007-01-30 03:03:46 +0000577
Benjamin Petersond5299862008-06-11 01:31:28 +0000578def test_main():
579 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000580
Benjamin Petersond5299862008-06-11 01:31:28 +0000581if __name__ == '__main__':
582 test_main()