blob: ec4a2dbc43eac81007827b892164be6bc8e73056 [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"
Mark Hammond69ed5242008-08-23 00:59:14 +000011IS32BIT = sys.maxsize == 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():
Nick Coghlan38469e22008-07-13 12:23:47 +000038 # We need this function to warn every time, so stick an
39 # unqualifed 'always' at the head of the filter list
40 warnings.simplefilter("always")
Benjamin Petersond5299862008-06-11 01:31:28 +000041 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000042 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000043 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000044
Benjamin Petersond5299862008-06-11 01:31:28 +000045@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000046def deprecated_err(func, *args):
47 try:
48 func(*args)
49 except (struct.error, TypeError):
50 pass
51 except DeprecationWarning:
52 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlan38469e22008-07-13 12:23:47 +000053 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000054 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000055 else:
56 raise TestFailed, "%s%s did not raise error" % (
57 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000058
Tim Peters17e17d42001-06-13 22:45:27 +000059
Benjamin Petersond5299862008-06-11 01:31:28 +000060class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000061
Benjamin Petersond5299862008-06-11 01:31:28 +000062 @with_warning_restore
63 def check_float_coerce(self, format, number):
64 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
65 if PY_STRUCT_FLOAT_COERCE == 2:
66 # Test for pre-2.5 struct module
67 packed = struct.pack(format, number)
68 floored = struct.unpack(format, packed)[0]
69 self.assertEqual(floored, int(number),
70 "did not correcly coerce float to int")
71 return
72 try:
73 struct.pack(format, number)
74 except (struct.error, TypeError):
75 if PY_STRUCT_FLOAT_COERCE:
76 self.fail("expected DeprecationWarning for float coerce")
77 except DeprecationWarning:
78 if not PY_STRUCT_FLOAT_COERCE:
79 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000080 else:
Benjamin Petersond5299862008-06-11 01:31:28 +000081 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000082
Benjamin Petersond5299862008-06-11 01:31:28 +000083 def test_isbigendian(self):
84 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000085
Benjamin Petersond5299862008-06-11 01:31:28 +000086 def test_consistence(self):
87 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Benjamin Petersond5299862008-06-11 01:31:28 +000089 sz = struct.calcsize('i')
90 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000091
Benjamin Petersond5299862008-06-11 01:31:28 +000092 fmt = 'cbxxxxxxhhhhiillffd?'
93 fmt3 = '3c3b18x12h6i6l6f3d3?'
94 sz = struct.calcsize(fmt)
95 sz3 = struct.calcsize(fmt3)
96 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000097
Benjamin Petersond5299862008-06-11 01:31:28 +000098 self.assertRaises(struct.error, struct.pack, 'iii', 3)
99 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
100 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
101 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
102 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
103 s = struct.pack('ii', 1, 2)
104 self.assertRaises(struct.error, struct.unpack, 'iii', s)
105 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000106
Benjamin Petersond5299862008-06-11 01:31:28 +0000107 def test_transitiveness(self):
108 c = 'a'
109 b = 1
110 h = 255
111 i = 65535
112 l = 65536
113 f = 3.1415
114 d = 3.1415
115 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000116
Benjamin Petersond5299862008-06-11 01:31:28 +0000117 for prefix in ('', '@', '<', '>', '=', '!'):
118 for format in ('xcbhilfd?', 'xcBHILfd?'):
119 format = prefix + format
120 s = struct.pack(format, c, b, h, i, l, f, d, t)
121 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
122 self.assertEqual(cp, c)
123 self.assertEqual(bp, b)
124 self.assertEqual(hp, h)
125 self.assertEqual(ip, i)
126 self.assertEqual(lp, l)
127 self.assertEqual(int(100 * fp), int(100 * f))
128 self.assertEqual(int(100 * dp), int(100 * d))
129 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000130
Benjamin Petersond5299862008-06-11 01:31:28 +0000131 def test_new_features(self):
132 # Test some of the new features in detail
133 # (format, argument, big-endian result, little-endian result, asymmetric)
134 tests = [
135 ('c', 'a', 'a', 'a', 0),
136 ('xc', 'a', '\0a', '\0a', 0),
137 ('cx', 'a', 'a\0', 'a\0', 0),
138 ('s', 'a', 'a', 'a', 0),
139 ('0s', 'helloworld', '', '', 1),
140 ('1s', 'helloworld', 'h', 'h', 1),
141 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
142 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
143 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
144 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
145 ('b', 7, '\7', '\7', 0),
146 ('b', -7, '\371', '\371', 0),
147 ('B', 7, '\7', '\7', 0),
148 ('B', 249, '\371', '\371', 0),
149 ('h', 700, '\002\274', '\274\002', 0),
150 ('h', -700, '\375D', 'D\375', 0),
151 ('H', 700, '\002\274', '\274\002', 0),
152 ('H', 0x10000-700, '\375D', 'D\375', 0),
153 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
154 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
155 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
156 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
158 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
159 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
160 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
161 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
162 ('d', 2.0, '@\000\000\000\000\000\000\000',
163 '\000\000\000\000\000\000\000@', 0),
164 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
165 ('d', -2.0, '\300\000\000\000\000\000\000\000',
166 '\000\000\000\000\000\000\000\300', 0),
167 ('?', 0, '\0', '\0', 0),
168 ('?', 3, '\1', '\1', 1),
169 ('?', True, '\1', '\1', 0),
170 ('?', [], '\0', '\0', 1),
171 ('?', (1,), '\1', '\1', 1),
172 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000173
Benjamin Petersond5299862008-06-11 01:31:28 +0000174 for fmt, arg, big, lil, asy in tests:
175 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
176 ('='+fmt, ISBIGENDIAN and big or lil)]:
177 res = struct.pack(xfmt, arg)
178 self.assertEqual(res, exp)
179 self.assertEqual(struct.calcsize(xfmt), len(res))
180 rev = struct.unpack(xfmt, res)[0]
181 if rev != arg:
182 self.assert_(asy)
183
184 def test_native_qQ(self):
185 # can't pack -1 as unsigned regardless
186 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
187 # can't pack string as 'q' regardless
188 self.assertRaises(struct.error, struct.pack, "q", "a")
189 # ditto, but 'Q'
190 self.assertRaises(struct.error, struct.pack, "Q", "a")
191
192 try:
193 struct.pack("q", 5)
194 except struct.error:
195 # does not have native q/Q
196 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000197 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000198 bytes = struct.calcsize('q')
199 # The expected values here are in big-endian format, primarily
200 # because I'm on a little-endian machine and so this is the
201 # clearest way (for me) to force the code to get exercised.
202 for format, input, expected in (
203 ('q', -1, '\xff' * bytes),
204 ('q', 0, '\x00' * bytes),
205 ('Q', 0, '\x00' * bytes),
206 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
207 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
208 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
209 got = struct.pack(format, input)
210 native_expected = bigendian_to_native(expected)
211 self.assertEqual(got, native_expected)
212 retrieved = struct.unpack(format, got)[0]
213 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000214
Benjamin Petersond5299862008-06-11 01:31:28 +0000215 def test_standard_integers(self):
216 # Standard integer tests (bBhHiIlLqQ).
217 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000218
Benjamin Petersond5299862008-06-11 01:31:28 +0000219 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000220
Benjamin Petersond5299862008-06-11 01:31:28 +0000221 # XXX Most std integer modes fail to test for out-of-range.
222 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
223 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
224 # reported by Mark Favas).
225 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000226
Benjamin Petersond5299862008-06-11 01:31:28 +0000227 def __init__(self, formatpair, bytesize):
228 self.assertEqual(len(formatpair), 2)
229 self.formatpair = formatpair
230 for direction in "<>!=":
231 for code in formatpair:
232 format = direction + code
233 self.assertEqual(struct.calcsize(format), bytesize)
234 self.bytesize = bytesize
235 self.bitsize = bytesize * 8
236 self.signed_code, self.unsigned_code = formatpair
237 self.unsigned_min = 0
238 self.unsigned_max = 2L**self.bitsize - 1
239 self.signed_min = -(2L**(self.bitsize-1))
240 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000241
Benjamin Petersond5299862008-06-11 01:31:28 +0000242 def test_one(self, x, pack=struct.pack,
243 unpack=struct.unpack,
244 unhexlify=binascii.unhexlify):
245 # Try signed.
246 code = self.signed_code
247 if self.signed_min <= x <= self.signed_max:
248 # Try big-endian.
249 expected = long(x)
250 if x < 0:
251 expected += 1L << self.bitsize
252 self.assert_(expected > 0)
253 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
254 if len(expected) & 1:
255 expected = "0" + expected
256 expected = unhexlify(expected)
257 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000258
Benjamin Petersond5299862008-06-11 01:31:28 +0000259 # Pack work?
260 format = ">" + code
261 got = pack(format, x)
262 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000263
Benjamin Petersond5299862008-06-11 01:31:28 +0000264 # Unpack work?
265 retrieved = unpack(format, got)[0]
266 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000267
Benjamin Petersond5299862008-06-11 01:31:28 +0000268 # Adding any byte should cause a "too big" error.
269 self.assertRaises((struct.error, TypeError), unpack, format,
270 '\x01' + got)
271 # Try little-endian.
272 format = "<" + code
273 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000274
Benjamin Petersond5299862008-06-11 01:31:28 +0000275 # Pack work?
276 got = pack(format, x)
277 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000278
Benjamin Petersond5299862008-06-11 01:31:28 +0000279 # Unpack work?
280 retrieved = unpack(format, got)[0]
281 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000282
Benjamin Petersond5299862008-06-11 01:31:28 +0000283 # Adding any byte should cause a "too big" error.
284 self.assertRaises((struct.error, TypeError), unpack, format,
285 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000286
Benjamin Petersond5299862008-06-11 01:31:28 +0000287 else:
288 # x is out of range -- verify pack realizes that.
289 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
290 if verbose:
291 print "Skipping buggy range check for code", code
292 else:
293 deprecated_err(pack, ">" + code, x)
294 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000295
Benjamin Petersond5299862008-06-11 01:31:28 +0000296 # Much the same for unsigned.
297 code = self.unsigned_code
298 if self.unsigned_min <= x <= self.unsigned_max:
299 # Try big-endian.
300 format = ">" + code
301 expected = long(x)
302 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
303 if len(expected) & 1:
304 expected = "0" + expected
305 expected = unhexlify(expected)
306 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000307
Benjamin Petersond5299862008-06-11 01:31:28 +0000308 # Pack work?
309 got = pack(format, x)
310 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000311
Benjamin Petersond5299862008-06-11 01:31:28 +0000312 # Unpack work?
313 retrieved = unpack(format, got)[0]
314 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000315
Benjamin Petersond5299862008-06-11 01:31:28 +0000316 # Adding any byte should cause a "too big" error.
317 self.assertRaises((struct.error, TypeError), unpack, format,
318 '\x01' + got)
319
320 # Try little-endian.
321 format = "<" + code
322 expected = string_reverse(expected)
323
324 # Pack work?
325 got = pack(format, x)
326 self.assertEqual(got, expected)
327
328 # Unpack work?
329 retrieved = unpack(format, got)[0]
330 self.assertEqual(x, retrieved)
331
332 # Adding any byte should cause a "too big" error.
333 self.assertRaises((struct.error, TypeError), unpack, format,
334 '\x01' + got)
335
336 else:
337 # x is out of range -- verify pack realizes that.
338 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
339 if verbose:
340 print "Skipping buggy range check for code", code
341 else:
342 deprecated_err(pack, ">" + code, x)
343 deprecated_err(pack, "<" + code, x)
344
345 def run(self):
346 from random import randrange
347
348 # Create all interesting powers of 2.
349 values = []
350 for exp in range(self.bitsize + 3):
351 values.append(1L << exp)
352
353 # Add some random values.
354 for i in range(self.bitsize):
355 val = 0L
356 for j in range(self.bytesize):
357 val = (val << 8) | randrange(256)
358 values.append(val)
359
360 # Try all those, and their negations, and +-1 from them. Note
361 # that this tests all power-of-2 boundaries in range, and a few out
362 # of range, plus +-(2**n +- 1).
363 for base in values:
364 for val in -base, base:
365 for incr in -1, 0, 1:
366 x = val + incr
367 try:
368 x = int(x)
369 except OverflowError:
370 pass
371 self.test_one(x)
372
373 # Some error cases.
374 for direction in "<>":
375 for code in self.formatpair:
376 for badobject in "a string", 3+42j, randrange:
377 self.assertRaises((struct.error, TypeError),
378 struct.pack, direction + code,
379 badobject)
380
381 for args in [("bB", 1),
382 ("hH", 2),
383 ("iI", 4),
384 ("lL", 4),
385 ("qQ", 8)]:
386 t = IntTester(*args)
387 t.run()
388
389 def test_p_code(self):
390 # Test p ("Pascal string") code.
391 for code, input, expected, expectedback in [
392 ('p','abc', '\x00', ''),
393 ('1p', 'abc', '\x00', ''),
394 ('2p', 'abc', '\x01a', 'a'),
395 ('3p', 'abc', '\x02ab', 'ab'),
396 ('4p', 'abc', '\x03abc', 'abc'),
397 ('5p', 'abc', '\x03abc\x00', 'abc'),
398 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
399 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
400 got = struct.pack(code, input)
401 self.assertEqual(got, expected)
402 (got,) = struct.unpack(code, got)
403 self.assertEqual(got, expectedback)
404
405 def test_705836(self):
406 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
407 # from the low-order discarded bits could propagate into the exponent
408 # field, causing the result to be wrong by a factor of 2.
409 import math
410
411 for base in range(1, 33):
412 # smaller <- largest representable float less than base.
413 delta = 0.5
414 while base - delta / 2.0 != base:
415 delta /= 2.0
416 smaller = base - delta
417 # Packing this rounds away a solid string of trailing 1 bits.
418 packed = struct.pack("<f", smaller)
419 unpacked = struct.unpack("<f", packed)[0]
420 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
421 # 16, respectively.
422 self.assertEqual(base, unpacked)
423 bigpacked = struct.pack(">f", smaller)
424 self.assertEqual(bigpacked, string_reverse(packed))
425 unpacked = struct.unpack(">f", bigpacked)[0]
426 self.assertEqual(base, unpacked)
427
428 # Largest finite IEEE single.
429 big = (1 << 24) - 1
430 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000431 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000432 unpacked = struct.unpack(">f", packed)[0]
433 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000434
Benjamin Petersond5299862008-06-11 01:31:28 +0000435 # The same, but tack on a 1 bit so it rounds up to infinity.
436 big = (1 << 25) - 1
437 big = math.ldexp(big, 127 - 24)
438 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000439
Benjamin Petersond5299862008-06-11 01:31:28 +0000440 if PY_STRUCT_RANGE_CHECKING:
441 def test_1229380(self):
442 # SF bug 1229380. No struct.pack exception for some out of
443 # range integers
444 import sys
445 for endian in ('', '>', '<'):
446 for cls in (int, long):
447 for fmt in ('B', 'H', 'I', 'L'):
448 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000449
Benjamin Petersond5299862008-06-11 01:31:28 +0000450 deprecated_err(struct.pack, endian + 'B', cls(300))
451 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000452
Benjamin Petersond5299862008-06-11 01:31:28 +0000453 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
454 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000455
Benjamin Petersond5299862008-06-11 01:31:28 +0000456 def XXXtest_1530559(self):
457 # XXX This is broken: see the bug report
458 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
459 for endian in ('', '>', '<'):
460 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
461 self.check_float_coerce(endian + fmt, 1.0)
462 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000463
Benjamin Petersond5299862008-06-11 01:31:28 +0000464 def test_unpack_from(self):
465 test_string = 'abcd01234'
466 fmt = '4s'
467 s = struct.Struct(fmt)
468 for cls in (str, buffer):
469 data = cls(test_string)
470 self.assertEqual(s.unpack_from(data), ('abcd',))
471 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
472 self.assertEqual(s.unpack_from(data, 4), ('0123',))
473 for i in xrange(6):
474 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
475 for i in xrange(6, len(test_string) + 1):
476 self.assertRaises(struct.error, s.unpack_from, data, i)
477 for cls in (str, buffer):
478 data = cls(test_string)
479 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
480 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
481 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
482 for i in xrange(6):
483 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
484 for i in xrange(6, len(test_string) + 1):
485 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000486
Benjamin Petersond5299862008-06-11 01:31:28 +0000487 def test_pack_into(self):
488 test_string = 'Reykjavik rocks, eow!'
489 writable_buf = array.array('c', ' '*100)
490 fmt = '21s'
491 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000492
Benjamin Petersond5299862008-06-11 01:31:28 +0000493 # Test without offset
494 s.pack_into(writable_buf, 0, test_string)
495 from_buf = writable_buf.tostring()[:len(test_string)]
496 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000497
Benjamin Petersond5299862008-06-11 01:31:28 +0000498 # Test with offset.
499 s.pack_into(writable_buf, 10, test_string)
500 from_buf = writable_buf.tostring()[:len(test_string)+10]
501 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000502
Benjamin Petersond5299862008-06-11 01:31:28 +0000503 # Go beyond boundaries.
504 small_buf = array.array('c', ' '*10)
505 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
506 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000507
Benjamin Petersond5299862008-06-11 01:31:28 +0000508 def test_pack_into_fn(self):
509 test_string = 'Reykjavik rocks, eow!'
510 writable_buf = array.array('c', ' '*100)
511 fmt = '21s'
512 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000513
Benjamin Petersond5299862008-06-11 01:31:28 +0000514 # Test without offset.
515 pack_into(writable_buf, 0, test_string)
516 from_buf = writable_buf.tostring()[:len(test_string)]
517 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000518
Benjamin Petersond5299862008-06-11 01:31:28 +0000519 # Test with offset.
520 pack_into(writable_buf, 10, test_string)
521 from_buf = writable_buf.tostring()[:len(test_string)+10]
522 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000523
Benjamin Petersond5299862008-06-11 01:31:28 +0000524 # Go beyond boundaries.
525 small_buf = array.array('c', ' '*10)
526 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
527 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000528
Benjamin Petersond5299862008-06-11 01:31:28 +0000529 def test_unpack_with_buffer(self):
530 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
531 data1 = array.array('B', '\x12\x34\x56\x78')
532 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
533 for data in [data1, data2]:
534 value, = struct.unpack('>I', data)
535 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000536
Benjamin Petersond5299862008-06-11 01:31:28 +0000537 def test_bool(self):
538 for prefix in tuple("<>!=")+('',):
539 false = (), [], [], '', 0
540 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000541
Benjamin Petersond5299862008-06-11 01:31:28 +0000542 falseFormat = prefix + '?' * len(false)
543 packedFalse = struct.pack(falseFormat, *false)
544 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000545
Benjamin Petersond5299862008-06-11 01:31:28 +0000546 trueFormat = prefix + '?' * len(true)
547 packedTrue = struct.pack(trueFormat, *true)
548 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000549
Benjamin Petersond5299862008-06-11 01:31:28 +0000550 self.assertEqual(len(true), len(unpackedTrue))
551 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000552
Benjamin Petersond5299862008-06-11 01:31:28 +0000553 for t in unpackedFalse:
554 self.assertFalse(t)
555 for t in unpackedTrue:
556 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000557
Benjamin Petersond5299862008-06-11 01:31:28 +0000558 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000559
Benjamin Petersond5299862008-06-11 01:31:28 +0000560 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000561
Benjamin Petersond5299862008-06-11 01:31:28 +0000562 if len(packed) != 1:
563 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
564 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000565
Benjamin Petersond5299862008-06-11 01:31:28 +0000566 for c in '\x01\x7f\xff\x0f\xf0':
567 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000568
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000569 if IS32BIT:
570 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000571 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000572
573
Tim Petersf733abb2007-01-30 03:03:46 +0000574
Benjamin Petersond5299862008-06-11 01:31:28 +0000575def test_main():
576 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000577
Benjamin Petersond5299862008-06-11 01:31:28 +0000578if __name__ == '__main__':
579 test_main()