blob: e3a4e21784448fb5b7fc34ea00459884a434ff7f [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"
11del sys
Tim Peters17e17d42001-06-13 22:45:27 +000012
Bob Ippolito2fd39772006-05-29 22:55:48 +000013try:
14 import _struct
15except ImportError:
16 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000017 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000018 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000019else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000020 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
21 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
22 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000023
Tim Peters17e17d42001-06-13 22:45:27 +000024def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000025 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000026
27def bigendian_to_native(value):
28 if ISBIGENDIAN:
29 return value
30 else:
31 return string_reverse(value)
32
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000033def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000034 @wraps(func)
35 def decorator(*args, **kw):
36 with catch_warning():
Brett Cannon6d9520c2006-12-13 23:09:53 +000037 # Grrr, we need this function to warn every time. Without removing
38 # the warningregistry, running test_tarfile then test_struct would fail
39 # on 64-bit platforms.
40 globals = func.func_globals
41 if '__warningregistry__' in globals:
42 del globals['__warningregistry__']
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)
51 except (struct.error, TypeError):
52 pass
53 except DeprecationWarning:
54 if not PY_STRUCT_OVERFLOW_MASKING:
55 raise TestFailed, "%s%s expected to raise struct.error" % (
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
188 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
189 # 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
Benjamin Petersond5299862008-06-11 01:31:28 +0000466 def test_unpack_from(self):
467 test_string = 'abcd01234'
468 fmt = '4s'
469 s = struct.Struct(fmt)
470 for cls in (str, buffer):
471 data = cls(test_string)
472 self.assertEqual(s.unpack_from(data), ('abcd',))
473 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
474 self.assertEqual(s.unpack_from(data, 4), ('0123',))
475 for i in xrange(6):
476 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
477 for i in xrange(6, len(test_string) + 1):
478 self.assertRaises(struct.error, s.unpack_from, data, i)
479 for cls in (str, buffer):
480 data = cls(test_string)
481 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
482 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
483 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
484 for i in xrange(6):
485 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
486 for i in xrange(6, len(test_string) + 1):
487 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000488
Benjamin Petersond5299862008-06-11 01:31:28 +0000489 def test_pack_into(self):
490 test_string = 'Reykjavik rocks, eow!'
491 writable_buf = array.array('c', ' '*100)
492 fmt = '21s'
493 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000494
Benjamin Petersond5299862008-06-11 01:31:28 +0000495 # Test without offset
496 s.pack_into(writable_buf, 0, test_string)
497 from_buf = writable_buf.tostring()[:len(test_string)]
498 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000499
Benjamin Petersond5299862008-06-11 01:31:28 +0000500 # Test with offset.
501 s.pack_into(writable_buf, 10, test_string)
502 from_buf = writable_buf.tostring()[:len(test_string)+10]
503 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000504
Benjamin Petersond5299862008-06-11 01:31:28 +0000505 # Go beyond boundaries.
506 small_buf = array.array('c', ' '*10)
507 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
508 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000509
Benjamin Petersond5299862008-06-11 01:31:28 +0000510 def test_pack_into_fn(self):
511 test_string = 'Reykjavik rocks, eow!'
512 writable_buf = array.array('c', ' '*100)
513 fmt = '21s'
514 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000515
Benjamin Petersond5299862008-06-11 01:31:28 +0000516 # Test without offset.
517 pack_into(writable_buf, 0, test_string)
518 from_buf = writable_buf.tostring()[:len(test_string)]
519 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000520
Benjamin Petersond5299862008-06-11 01:31:28 +0000521 # Test with offset.
522 pack_into(writable_buf, 10, test_string)
523 from_buf = writable_buf.tostring()[:len(test_string)+10]
524 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000525
Benjamin Petersond5299862008-06-11 01:31:28 +0000526 # Go beyond boundaries.
527 small_buf = array.array('c', ' '*10)
528 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
529 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000530
Benjamin Petersond5299862008-06-11 01:31:28 +0000531 def test_unpack_with_buffer(self):
532 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
533 data1 = array.array('B', '\x12\x34\x56\x78')
534 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
535 for data in [data1, data2]:
536 value, = struct.unpack('>I', data)
537 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000538
Benjamin Petersond5299862008-06-11 01:31:28 +0000539 def test_bool(self):
540 for prefix in tuple("<>!=")+('',):
541 false = (), [], [], '', 0
542 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000543
Benjamin Petersond5299862008-06-11 01:31:28 +0000544 falseFormat = prefix + '?' * len(false)
545 packedFalse = struct.pack(falseFormat, *false)
546 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000547
Benjamin Petersond5299862008-06-11 01:31:28 +0000548 trueFormat = prefix + '?' * len(true)
549 packedTrue = struct.pack(trueFormat, *true)
550 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000551
Benjamin Petersond5299862008-06-11 01:31:28 +0000552 self.assertEqual(len(true), len(unpackedTrue))
553 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000554
Benjamin Petersond5299862008-06-11 01:31:28 +0000555 for t in unpackedFalse:
556 self.assertFalse(t)
557 for t in unpackedTrue:
558 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000559
Benjamin Petersond5299862008-06-11 01:31:28 +0000560 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000561
Benjamin Petersond5299862008-06-11 01:31:28 +0000562 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000563
Benjamin Petersond5299862008-06-11 01:31:28 +0000564 if len(packed) != 1:
565 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
566 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000567
Benjamin Petersond5299862008-06-11 01:31:28 +0000568 for c in '\x01\x7f\xff\x0f\xf0':
569 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000570
Tim Petersf733abb2007-01-30 03:03:46 +0000571
Benjamin Petersond5299862008-06-11 01:31:28 +0000572def test_main():
573 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000574
Benjamin Petersond5299862008-06-11 01:31:28 +0000575if __name__ == '__main__':
576 test_main()