blob: ca85f8f161561d6f8c5d4c8d1f6327a887d587e4 [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
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000014
15integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
16
17# Native 'q' packing isn't available on systems that don't have the C
18# long long type.
19try:
20 struct.pack('q', 5)
21except struct.error:
22 HAVE_LONG_LONG = False
23else:
24 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000025
Bob Ippolito2fd39772006-05-29 22:55:48 +000026try:
27 import _struct
28except ImportError:
29 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000030 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000031 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000032else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000033 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
34 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
35 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000036
Tim Peters17e17d42001-06-13 22:45:27 +000037def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000038 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000039
40def bigendian_to_native(value):
41 if ISBIGENDIAN:
42 return value
43 else:
44 return string_reverse(value)
45
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000046def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000047 @wraps(func)
48 def decorator(*args, **kw):
Brett Cannon672237d2008-09-09 00:49:16 +000049 with warnings.catch_warnings():
Nick Coghlan38469e22008-07-13 12:23:47 +000050 # We need this function to warn every time, so stick an
51 # unqualifed 'always' at the head of the filter list
52 warnings.simplefilter("always")
Benjamin Petersond5299862008-06-11 01:31:28 +000053 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000054 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000055 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000056
Benjamin Petersond5299862008-06-11 01:31:28 +000057@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000058def deprecated_err(func, *args):
59 try:
60 func(*args)
Mark Dickinson4015f622009-02-10 15:46:50 +000061 except (struct.error, OverflowError):
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000062 pass
63 except DeprecationWarning:
64 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlan38469e22008-07-13 12:23:47 +000065 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000066 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000067 else:
68 raise TestFailed, "%s%s did not raise error" % (
69 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000070
Benjamin Petersond5299862008-06-11 01:31:28 +000071class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000072
Benjamin Petersond5299862008-06-11 01:31:28 +000073 @with_warning_restore
74 def check_float_coerce(self, format, number):
75 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
76 if PY_STRUCT_FLOAT_COERCE == 2:
77 # Test for pre-2.5 struct module
78 packed = struct.pack(format, number)
79 floored = struct.unpack(format, packed)[0]
80 self.assertEqual(floored, int(number),
81 "did not correcly coerce float to int")
82 return
83 try:
84 struct.pack(format, number)
Mark Dickinson463dc4b2009-07-05 10:01:24 +000085 except struct.error:
Benjamin Petersond5299862008-06-11 01:31:28 +000086 if PY_STRUCT_FLOAT_COERCE:
87 self.fail("expected DeprecationWarning for float coerce")
88 except DeprecationWarning:
89 if not PY_STRUCT_FLOAT_COERCE:
90 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000091 else:
Benjamin Petersond5299862008-06-11 01:31:28 +000092 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Benjamin Petersond5299862008-06-11 01:31:28 +000094 def test_isbigendian(self):
95 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000096
Benjamin Petersond5299862008-06-11 01:31:28 +000097 def test_consistence(self):
98 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000099
Benjamin Petersond5299862008-06-11 01:31:28 +0000100 sz = struct.calcsize('i')
101 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +0000102
Benjamin Petersond5299862008-06-11 01:31:28 +0000103 fmt = 'cbxxxxxxhhhhiillffd?'
104 fmt3 = '3c3b18x12h6i6l6f3d3?'
105 sz = struct.calcsize(fmt)
106 sz3 = struct.calcsize(fmt3)
107 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000108
Benjamin Petersond5299862008-06-11 01:31:28 +0000109 self.assertRaises(struct.error, struct.pack, 'iii', 3)
110 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
111 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
112 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
113 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
114 s = struct.pack('ii', 1, 2)
115 self.assertRaises(struct.error, struct.unpack, 'iii', s)
116 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000117
Benjamin Petersond5299862008-06-11 01:31:28 +0000118 def test_transitiveness(self):
119 c = 'a'
120 b = 1
121 h = 255
122 i = 65535
123 l = 65536
124 f = 3.1415
125 d = 3.1415
126 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000127
Benjamin Petersond5299862008-06-11 01:31:28 +0000128 for prefix in ('', '@', '<', '>', '=', '!'):
129 for format in ('xcbhilfd?', 'xcBHILfd?'):
130 format = prefix + format
131 s = struct.pack(format, c, b, h, i, l, f, d, t)
132 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
133 self.assertEqual(cp, c)
134 self.assertEqual(bp, b)
135 self.assertEqual(hp, h)
136 self.assertEqual(ip, i)
137 self.assertEqual(lp, l)
138 self.assertEqual(int(100 * fp), int(100 * f))
139 self.assertEqual(int(100 * dp), int(100 * d))
140 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000141
Benjamin Petersond5299862008-06-11 01:31:28 +0000142 def test_new_features(self):
143 # Test some of the new features in detail
144 # (format, argument, big-endian result, little-endian result, asymmetric)
145 tests = [
146 ('c', 'a', 'a', 'a', 0),
147 ('xc', 'a', '\0a', '\0a', 0),
148 ('cx', 'a', 'a\0', 'a\0', 0),
149 ('s', 'a', 'a', 'a', 0),
150 ('0s', 'helloworld', '', '', 1),
151 ('1s', 'helloworld', 'h', 'h', 1),
152 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
153 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
154 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
155 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
156 ('b', 7, '\7', '\7', 0),
157 ('b', -7, '\371', '\371', 0),
158 ('B', 7, '\7', '\7', 0),
159 ('B', 249, '\371', '\371', 0),
160 ('h', 700, '\002\274', '\274\002', 0),
161 ('h', -700, '\375D', 'D\375', 0),
162 ('H', 700, '\002\274', '\274\002', 0),
163 ('H', 0x10000-700, '\375D', 'D\375', 0),
164 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
165 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
166 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
167 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
168 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
169 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
170 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
171 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
172 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
173 ('d', 2.0, '@\000\000\000\000\000\000\000',
174 '\000\000\000\000\000\000\000@', 0),
175 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
176 ('d', -2.0, '\300\000\000\000\000\000\000\000',
177 '\000\000\000\000\000\000\000\300', 0),
178 ('?', 0, '\0', '\0', 0),
179 ('?', 3, '\1', '\1', 1),
180 ('?', True, '\1', '\1', 0),
181 ('?', [], '\0', '\0', 1),
182 ('?', (1,), '\1', '\1', 1),
183 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000184
Benjamin Petersond5299862008-06-11 01:31:28 +0000185 for fmt, arg, big, lil, asy in tests:
186 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
187 ('='+fmt, ISBIGENDIAN and big or lil)]:
188 res = struct.pack(xfmt, arg)
189 self.assertEqual(res, exp)
190 self.assertEqual(struct.calcsize(xfmt), len(res))
191 rev = struct.unpack(xfmt, res)[0]
192 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000193 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000194
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000195 def test_calcsize(self):
196 expected_size = {
197 'b': 1, 'B': 1,
198 'h': 2, 'H': 2,
199 'i': 4, 'I': 4,
200 'l': 4, 'L': 4,
201 'q': 8, 'Q': 8,
202 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000203
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000204 # standard integer sizes
205 for code in integer_codes:
206 for byteorder in ('=', '<', '>', '!'):
207 format = byteorder+code
208 size = struct.calcsize(format)
209 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000210
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000211 # native integer sizes, except 'q' and 'Q'
212 for format_pair in ('bB', 'hH', 'iI', 'lL'):
213 for byteorder in ['', '@']:
214 signed_size = struct.calcsize(byteorder + format_pair[0])
215 unsigned_size = struct.calcsize(byteorder + format_pair[1])
216 self.assertEqual(signed_size, unsigned_size)
217
218 # bounds for native integer sizes
219 self.assertTrue(struct.calcsize('b')==1)
220 self.assertTrue(2 <= struct.calcsize('h'))
221 self.assertTrue(4 <= struct.calcsize('l'))
222 self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
223 self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
224
225 # tests for native 'q' and 'Q' when applicable
226 if HAVE_LONG_LONG:
227 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
228 self.assertTrue(8 <= struct.calcsize('q'))
229 self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
230
231 def test_integers(self):
232 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000233 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000234
Benjamin Petersond5299862008-06-11 01:31:28 +0000235 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000236 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000237 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000238 self.format = format
239 self.code = format[-1]
240 self.direction = format[:-1]
241 if not self.direction in ('', '@', '=', '<', '>', '!'):
242 raise ValueError("unrecognized packing direction: %s" %
243 self.direction)
244 self.bytesize = struct.calcsize(format)
245 self.bitsize = self.bytesize * 8
246 if self.code in tuple('bhilq'):
247 self.signed = True
248 self.min_value = -(2L**(self.bitsize-1))
249 self.max_value = 2L**(self.bitsize-1) - 1
250 elif self.code in tuple('BHILQ'):
251 self.signed = False
252 self.min_value = 0
253 self.max_value = 2L**self.bitsize - 1
254 else:
255 raise ValueError("unrecognized format code: %s" %
256 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000257
Benjamin Petersond5299862008-06-11 01:31:28 +0000258 def test_one(self, x, pack=struct.pack,
259 unpack=struct.unpack,
260 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000261
262 format = self.format
263 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000264 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000265 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000266 expected += 1L << self.bitsize
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000267 self.assertTrue(expected >= 0)
268 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000269 if len(expected) & 1:
270 expected = "0" + expected
271 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000272 expected = ("\x00" * (self.bytesize - len(expected)) +
273 expected)
274 if (self.direction == '<' or
275 self.direction in ('', '@', '=') and not ISBIGENDIAN):
276 expected = string_reverse(expected)
277 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000278
Benjamin Petersond5299862008-06-11 01:31:28 +0000279 # Pack work?
280 got = pack(format, x)
281 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000282
Benjamin Petersond5299862008-06-11 01:31:28 +0000283 # Unpack work?
284 retrieved = unpack(format, got)[0]
285 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000286
Benjamin Petersond5299862008-06-11 01:31:28 +0000287 # Adding any byte should cause a "too big" error.
288 self.assertRaises((struct.error, TypeError), unpack, format,
289 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000290 else:
291 # x is out of range -- verify pack realizes that.
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000292 deprecated_err(pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000293
294 def run(self):
295 from random import randrange
296
297 # Create all interesting powers of 2.
298 values = []
299 for exp in range(self.bitsize + 3):
300 values.append(1L << exp)
301
302 # Add some random values.
303 for i in range(self.bitsize):
304 val = 0L
305 for j in range(self.bytesize):
306 val = (val << 8) | randrange(256)
307 values.append(val)
308
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000309 # Values absorbed from other tests
310 values.extend([300, 700000, sys.maxint*4])
311
312 # Try all those, and their negations, and +-1 from
313 # them. Note that this tests all power-of-2
314 # boundaries in range, and a few out of range, plus
315 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000316 for base in values:
317 for val in -base, base:
318 for incr in -1, 0, 1:
319 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000320 self.test_one(int(x))
321 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000322
323 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000324 class NotAnIntNS(object):
325 def __int__(self):
326 return 42
327
328 def __long__(self):
329 return 1729L
330
331 class NotAnIntOS:
332 def __int__(self):
333 return 10585
334
335 def __long__(self):
336 return -163L
337
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000338 for badobject in ("a string", 3+42j, randrange,
339 NotAnIntNS(), NotAnIntOS()):
340 self.assertRaises(struct.error,
341 struct.pack, format,
342 badobject)
Benjamin Petersond5299862008-06-11 01:31:28 +0000343
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000344 byteorders = '', '@', '=', '<', '>', '!'
345 for code in integer_codes:
346 for byteorder in byteorders:
347 if (byteorder in ('', '@') and code in ('q', 'Q') and
348 not HAVE_LONG_LONG):
349 continue
350 format = byteorder+code
351 t = IntTester(format)
352 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000353
354 def test_p_code(self):
355 # Test p ("Pascal string") code.
356 for code, input, expected, expectedback in [
357 ('p','abc', '\x00', ''),
358 ('1p', 'abc', '\x00', ''),
359 ('2p', 'abc', '\x01a', 'a'),
360 ('3p', 'abc', '\x02ab', 'ab'),
361 ('4p', 'abc', '\x03abc', 'abc'),
362 ('5p', 'abc', '\x03abc\x00', 'abc'),
363 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
364 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
365 got = struct.pack(code, input)
366 self.assertEqual(got, expected)
367 (got,) = struct.unpack(code, got)
368 self.assertEqual(got, expectedback)
369
370 def test_705836(self):
371 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
372 # from the low-order discarded bits could propagate into the exponent
373 # field, causing the result to be wrong by a factor of 2.
374 import math
375
376 for base in range(1, 33):
377 # smaller <- largest representable float less than base.
378 delta = 0.5
379 while base - delta / 2.0 != base:
380 delta /= 2.0
381 smaller = base - delta
382 # Packing this rounds away a solid string of trailing 1 bits.
383 packed = struct.pack("<f", smaller)
384 unpacked = struct.unpack("<f", packed)[0]
385 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
386 # 16, respectively.
387 self.assertEqual(base, unpacked)
388 bigpacked = struct.pack(">f", smaller)
389 self.assertEqual(bigpacked, string_reverse(packed))
390 unpacked = struct.unpack(">f", bigpacked)[0]
391 self.assertEqual(base, unpacked)
392
393 # Largest finite IEEE single.
394 big = (1 << 24) - 1
395 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000396 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000397 unpacked = struct.unpack(">f", packed)[0]
398 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000399
Benjamin Petersond5299862008-06-11 01:31:28 +0000400 # The same, but tack on a 1 bit so it rounds up to infinity.
401 big = (1 << 25) - 1
402 big = math.ldexp(big, 127 - 24)
403 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000404
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000405 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000406 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
407 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000408 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000409 self.check_float_coerce(endian + fmt, 1.0)
410 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000411
Benjamin Petersond5299862008-06-11 01:31:28 +0000412 def test_unpack_from(self):
413 test_string = 'abcd01234'
414 fmt = '4s'
415 s = struct.Struct(fmt)
416 for cls in (str, buffer):
417 data = cls(test_string)
418 self.assertEqual(s.unpack_from(data), ('abcd',))
419 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
420 self.assertEqual(s.unpack_from(data, 4), ('0123',))
421 for i in xrange(6):
422 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
423 for i in xrange(6, len(test_string) + 1):
424 self.assertRaises(struct.error, s.unpack_from, data, i)
425 for cls in (str, buffer):
426 data = cls(test_string)
427 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
428 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
429 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
430 for i in xrange(6):
431 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
432 for i in xrange(6, len(test_string) + 1):
433 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000434
Benjamin Petersond5299862008-06-11 01:31:28 +0000435 def test_pack_into(self):
436 test_string = 'Reykjavik rocks, eow!'
437 writable_buf = array.array('c', ' '*100)
438 fmt = '21s'
439 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000440
Benjamin Petersond5299862008-06-11 01:31:28 +0000441 # Test without offset
442 s.pack_into(writable_buf, 0, test_string)
443 from_buf = writable_buf.tostring()[:len(test_string)]
444 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000445
Benjamin Petersond5299862008-06-11 01:31:28 +0000446 # Test with offset.
447 s.pack_into(writable_buf, 10, test_string)
448 from_buf = writable_buf.tostring()[:len(test_string)+10]
449 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000450
Benjamin Petersond5299862008-06-11 01:31:28 +0000451 # Go beyond boundaries.
452 small_buf = array.array('c', ' '*10)
453 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
454 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000455
Georg Brandl0638a082009-02-13 11:03:59 +0000456 # Test bogus offset (issue 3694)
457 sb = small_buf
458 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
459
Benjamin Petersond5299862008-06-11 01:31:28 +0000460 def test_pack_into_fn(self):
461 test_string = 'Reykjavik rocks, eow!'
462 writable_buf = array.array('c', ' '*100)
463 fmt = '21s'
464 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000465
Benjamin Petersond5299862008-06-11 01:31:28 +0000466 # Test without offset.
467 pack_into(writable_buf, 0, test_string)
468 from_buf = writable_buf.tostring()[:len(test_string)]
469 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000470
Benjamin Petersond5299862008-06-11 01:31:28 +0000471 # Test with offset.
472 pack_into(writable_buf, 10, test_string)
473 from_buf = writable_buf.tostring()[:len(test_string)+10]
474 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000475
Benjamin Petersond5299862008-06-11 01:31:28 +0000476 # Go beyond boundaries.
477 small_buf = array.array('c', ' '*10)
478 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
479 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000480
Benjamin Petersond5299862008-06-11 01:31:28 +0000481 def test_unpack_with_buffer(self):
482 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
483 data1 = array.array('B', '\x12\x34\x56\x78')
484 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
485 for data in [data1, data2]:
486 value, = struct.unpack('>I', data)
487 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000488
Benjamin Petersond5299862008-06-11 01:31:28 +0000489 def test_bool(self):
490 for prefix in tuple("<>!=")+('',):
491 false = (), [], [], '', 0
492 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000493
Benjamin Petersond5299862008-06-11 01:31:28 +0000494 falseFormat = prefix + '?' * len(false)
495 packedFalse = struct.pack(falseFormat, *false)
496 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000497
Benjamin Petersond5299862008-06-11 01:31:28 +0000498 trueFormat = prefix + '?' * len(true)
499 packedTrue = struct.pack(trueFormat, *true)
500 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000501
Benjamin Petersond5299862008-06-11 01:31:28 +0000502 self.assertEqual(len(true), len(unpackedTrue))
503 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000504
Benjamin Petersond5299862008-06-11 01:31:28 +0000505 for t in unpackedFalse:
506 self.assertFalse(t)
507 for t in unpackedTrue:
508 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000509
Benjamin Petersond5299862008-06-11 01:31:28 +0000510 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000511
Benjamin Petersond5299862008-06-11 01:31:28 +0000512 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000513
Benjamin Petersond5299862008-06-11 01:31:28 +0000514 if len(packed) != 1:
515 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
516 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000517
Benjamin Petersond5299862008-06-11 01:31:28 +0000518 for c in '\x01\x7f\xff\x0f\xf0':
519 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000520
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000521 if IS32BIT:
522 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000523 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000524
525
Tim Petersf733abb2007-01-30 03:03:46 +0000526
Benjamin Petersond5299862008-06-11 01:31:28 +0000527def test_main():
528 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000529
Benjamin Petersond5299862008-06-11 01:31:28 +0000530if __name__ == '__main__':
531 test_main()