blob: beeee8f07b97f01ca1abf55225a0fba015820254 [file] [log] [blame]
Thomas Wouters477c8d52006-05-27 19:21:47 +00001import array
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00002import unittest
3import struct
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00004import warnings
Barry Warsaw07a0eec1996-12-12 23:34:06 +00005
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00006from functools import wraps
Brett Cannon1cd02472008-09-09 01:52:27 +00007from test.support import TestFailed, verbose, run_unittest
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +000011IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000012del sys
Tim Peters17e17d42001-06-13 22:45:27 +000013
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000014try:
15 import _struct
16except ImportError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000017 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000018else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000020
Tim Peters17e17d42001-06-13 22:45:27 +000021def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000022 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000023
24def bigendian_to_native(value):
25 if ISBIGENDIAN:
26 return value
27 else:
28 return string_reverse(value)
29
Thomas Wouters0e3f5912006-08-11 14:57:12 +000030def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000031 @wraps(func)
32 def decorator(*args, **kw):
Brett Cannon1cd02472008-09-09 01:52:27 +000033 with warnings.catch_warnings():
Nick Coghlanb1304932008-07-13 12:25:08 +000034 # We need this function to warn every time, so stick an
35 # unqualifed 'always' at the head of the filter list
36 warnings.simplefilter("always")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000037 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000038 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000040
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000041class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000042
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 @with_warning_restore
44 def check_float_coerce(self, format, number):
45 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
46 if PY_STRUCT_FLOAT_COERCE == 2:
47 # Test for pre-2.5 struct module
48 packed = struct.pack(format, number)
49 floored = struct.unpack(format, packed)[0]
50 self.assertEqual(floored, int(number),
51 "did not correcly coerce float to int")
52 return
53 try:
54 struct.pack(format, number)
55 except (struct.error, TypeError):
56 if PY_STRUCT_FLOAT_COERCE:
57 self.fail("expected DeprecationWarning for float coerce")
58 except DeprecationWarning:
59 if not PY_STRUCT_FLOAT_COERCE:
60 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000061 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000063
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000064 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000065 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000066
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000067 def test_consistence(self):
68 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000069
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000070 sz = struct.calcsize('i')
71 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000072
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000073 fmt = 'cbxxxxxxhhhhiillffd?'
74 fmt3 = '3c3b18x12h6i6l6f3d3?'
75 sz = struct.calcsize(fmt)
76 sz3 = struct.calcsize(fmt3)
77 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000078
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000079 self.assertRaises(struct.error, struct.pack, 'iii', 3)
80 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
81 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
82 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
83 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
84 s = struct.pack('ii', 1, 2)
85 self.assertRaises(struct.error, struct.unpack, 'iii', s)
86 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000088 def test_transitiveness(self):
89 c = b'a'
90 b = 1
91 h = 255
92 i = 65535
93 l = 65536
94 f = 3.1415
95 d = 3.1415
96 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000097
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000098 for prefix in ('', '@', '<', '>', '=', '!'):
99 for format in ('xcbhilfd?', 'xcBHILfd?'):
100 format = prefix + format
101 s = struct.pack(format, c, b, h, i, l, f, d, t)
102 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
103 self.assertEqual(cp, c)
104 self.assertEqual(bp, b)
105 self.assertEqual(hp, h)
106 self.assertEqual(ip, i)
107 self.assertEqual(lp, l)
108 self.assertEqual(int(100 * fp), int(100 * f))
109 self.assertEqual(int(100 * dp), int(100 * d))
110 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000111
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000112 def test_new_features(self):
113 # Test some of the new features in detail
114 # (format, argument, big-endian result, little-endian result, asymmetric)
115 tests = [
116 ('c', 'a', 'a', 'a', 0),
117 ('xc', 'a', '\0a', '\0a', 0),
118 ('cx', 'a', 'a\0', 'a\0', 0),
119 ('s', 'a', 'a', 'a', 0),
120 ('0s', 'helloworld', '', '', 1),
121 ('1s', 'helloworld', 'h', 'h', 1),
122 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
123 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
124 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
125 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
126 ('b', 7, '\7', '\7', 0),
127 ('b', -7, '\371', '\371', 0),
128 ('B', 7, '\7', '\7', 0),
129 ('B', 249, '\371', '\371', 0),
130 ('h', 700, '\002\274', '\274\002', 0),
131 ('h', -700, '\375D', 'D\375', 0),
132 ('H', 700, '\002\274', '\274\002', 0),
133 ('H', 0x10000-700, '\375D', 'D\375', 0),
134 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
135 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
136 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
137 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
138 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
139 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
140 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
141 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
142 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
143 ('d', 2.0, '@\000\000\000\000\000\000\000',
144 '\000\000\000\000\000\000\000@', 0),
145 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
146 ('d', -2.0, '\300\000\000\000\000\000\000\000',
147 '\000\000\000\000\000\000\000\300', 0),
148 ('?', 0, '\0', '\0', 0),
149 ('?', 3, '\1', '\1', 1),
150 ('?', True, '\1', '\1', 0),
151 ('?', [], '\0', '\0', 1),
152 ('?', (1,), '\1', '\1', 1),
153 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000154
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000155 for fmt, arg, big, lil, asy in tests:
156 big = bytes(big, "latin-1")
157 lil = bytes(lil, "latin-1")
158 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
159 ('='+fmt, ISBIGENDIAN and big or lil)]:
160 res = struct.pack(xfmt, arg)
161 self.assertEqual(res, exp)
162 self.assertEqual(struct.calcsize(xfmt), len(res))
163 rev = struct.unpack(xfmt, res)[0]
164 if isinstance(arg, str):
165 # Strings are returned as bytes since you can't know the
166 # encoding of the string when packed.
167 arg = bytes(arg, 'latin1')
168 if rev != arg:
169 self.assert_(asy)
170
171 def test_native_qQ(self):
172 # can't pack -1 as unsigned regardless
Mark Dickinson21776072009-02-10 16:13:25 +0000173 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000174 # can't pack string as 'q' regardless
175 self.assertRaises(struct.error, struct.pack, "q", "a")
176 # ditto, but 'Q'
177 self.assertRaises(struct.error, struct.pack, "Q", "a")
178
179 try:
180 struct.pack("q", 5)
181 except struct.error:
182 # does not have native q/Q
183 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000184 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000185 nbytes = struct.calcsize('q')
186 # The expected values here are in big-endian format, primarily
187 # because I'm on a little-endian machine and so this is the
188 # clearest way (for me) to force the code to get exercised.
189 for format, input, expected in (
190 ('q', -1, '\xff' * nbytes),
191 ('q', 0, '\x00' * nbytes),
192 ('Q', 0, '\x00' * nbytes),
193 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
194 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
195 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
196 expected = bytes(expected, "latin-1")
197 got = struct.pack(format, input)
198 native_expected = bigendian_to_native(expected)
199 self.assertEqual(got, native_expected)
200 retrieved = struct.unpack(format, got)[0]
201 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000202
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000203 def test_standard_integers(self):
204 # Standard integer tests (bBhHiIlLqQ).
205 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000206
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000207 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000208
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000209 def __init__(self, formatpair, bytesize):
210 self.assertEqual(len(formatpair), 2)
211 self.formatpair = formatpair
212 for direction in "<>!=":
213 for code in formatpair:
214 format = direction + code
215 self.assertEqual(struct.calcsize(format), bytesize)
216 self.bytesize = bytesize
217 self.bitsize = bytesize * 8
218 self.signed_code, self.unsigned_code = formatpair
219 self.unsigned_min = 0
220 self.unsigned_max = 2**self.bitsize - 1
221 self.signed_min = -(2**(self.bitsize-1))
222 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 def test_one(self, x, pack=struct.pack,
225 unpack=struct.unpack,
226 unhexlify=binascii.unhexlify):
227 # Try signed.
228 code = self.signed_code
229 if self.signed_min <= x <= self.signed_max:
230 # Try big-endian.
231 expected = x
232 if x < 0:
233 expected += 1 << self.bitsize
234 self.assert_(expected > 0)
235 expected = hex(expected)[2:] # chop "0x"
236 if len(expected) & 1:
237 expected = "0" + expected
238 expected = unhexlify(expected)
239 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000240
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000241 # Pack work?
242 format = ">" + code
243 got = pack(format, x)
244 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000245
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000246 # Unpack work?
247 retrieved = unpack(format, got)[0]
248 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000249
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000250 # Adding any byte should cause a "too big" error.
251 self.assertRaises((struct.error, TypeError),
252 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000253
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000254 # Try little-endian.
255 format = "<" + code
256 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000257
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000258 # Pack work?
259 got = pack(format, x)
260 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000261
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000262 # Unpack work?
263 retrieved = unpack(format, got)[0]
264 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000265
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000266 # Adding any byte should cause a "too big" error.
267 self.assertRaises((struct.error, TypeError),
268 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000269
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000270 else:
271 # x is out of range -- verify pack realizes that.
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000272 self.assertRaises((struct.error, OverflowError),
273 pack, ">" + code, x)
274 self.assertRaises((struct.error, OverflowError),
275 pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000276
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000277 # Much the same for unsigned.
278 code = self.unsigned_code
279 if self.unsigned_min <= x <= self.unsigned_max:
280 # Try big-endian.
281 format = ">" + code
282 expected = x
283 expected = hex(expected)[2:] # chop "0x"
284 if len(expected) & 1:
285 expected = "0" + expected
286 expected = unhexlify(expected)
287 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000288
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000289 # Pack work?
290 got = pack(format, x)
291 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000292
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000293 # Unpack work?
294 retrieved = unpack(format, got)[0]
295 self.assertEqual(x, retrieved)
296
297 # Adding any byte should cause a "too big" error.
298 self.assertRaises((struct.error, TypeError),
299 unpack, format, b'\x01' + got)
300
301 # Try little-endian.
302 format = "<" + code
303 expected = string_reverse(expected)
304
305 # Pack work?
306 got = pack(format, x)
307 self.assertEqual(got, expected)
308
309 # Unpack work?
310 retrieved = unpack(format, got)[0]
311 self.assertEqual(x, retrieved)
312
313 # Adding any byte should cause a "too big" error.
314 self.assertRaises((struct.error, TypeError),
315 unpack, format, b'\x01' + got)
316
317 else:
318 # x is out of range -- verify pack realizes that.
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000319 self.assertRaises((struct.error, OverflowError),
320 pack, ">" + code, x)
321 self.assertRaises((struct.error, OverflowError),
322 pack, "<" + code, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000323
324 def run(self):
325 from random import randrange
326
327 # Create all interesting powers of 2.
328 values = []
329 for exp in range(self.bitsize + 3):
330 values.append(1 << exp)
331
332 # Add some random values.
333 for i in range(self.bitsize):
334 val = 0
335 for j in range(self.bytesize):
336 val = (val << 8) | randrange(256)
337 values.append(val)
338
339 # Try all those, and their negations, and +-1 from them. Note
340 # that this tests all power-of-2 boundaries in range, and a few out
341 # of range, plus +-(2**n +- 1).
342 for base in values:
343 for val in -base, base:
344 for incr in -1, 0, 1:
345 x = val + incr
346 try:
347 x = int(x)
348 except OverflowError:
349 pass
350 self.test_one(x)
351
352 # Some error cases.
353 for direction in "<>":
354 for code in self.formatpair:
355 for badobject in "a string", 3+42j, randrange:
356 self.assertRaises((struct.error, TypeError),
357 struct.pack, direction + code,
358 badobject)
359
360 for args in [("bB", 1),
361 ("hH", 2),
362 ("iI", 4),
363 ("lL", 4),
364 ("qQ", 8)]:
365 t = IntTester(*args)
366 t.run()
367
368 def test_p_code(self):
369 # Test p ("Pascal string") code.
370 for code, input, expected, expectedback in [
371 ('p','abc', '\x00', b''),
372 ('1p', 'abc', '\x00', b''),
373 ('2p', 'abc', '\x01a', b'a'),
374 ('3p', 'abc', '\x02ab', b'ab'),
375 ('4p', 'abc', '\x03abc', b'abc'),
376 ('5p', 'abc', '\x03abc\x00', b'abc'),
377 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
378 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
379 expected = bytes(expected, "latin-1")
380 got = struct.pack(code, input)
381 self.assertEqual(got, expected)
382 (got,) = struct.unpack(code, got)
383 self.assertEqual(got, expectedback)
384
385 def test_705836(self):
386 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
387 # from the low-order discarded bits could propagate into the exponent
388 # field, causing the result to be wrong by a factor of 2.
389 import math
390
391 for base in range(1, 33):
392 # smaller <- largest representable float less than base.
393 delta = 0.5
394 while base - delta / 2.0 != base:
395 delta /= 2.0
396 smaller = base - delta
397 # Packing this rounds away a solid string of trailing 1 bits.
398 packed = struct.pack("<f", smaller)
399 unpacked = struct.unpack("<f", packed)[0]
400 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
401 # 16, respectively.
402 self.assertEqual(base, unpacked)
403 bigpacked = struct.pack(">f", smaller)
404 self.assertEqual(bigpacked, string_reverse(packed))
405 unpacked = struct.unpack(">f", bigpacked)[0]
406 self.assertEqual(base, unpacked)
407
408 # Largest finite IEEE single.
409 big = (1 << 24) - 1
410 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000411 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000412 unpacked = struct.unpack(">f", packed)[0]
413 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000414
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000415 # The same, but tack on a 1 bit so it rounds up to infinity.
416 big = (1 << 25) - 1
417 big = math.ldexp(big, 127 - 24)
418 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000419
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000420 def test_1229380(self):
421 # SF bug 1229380. No struct.pack exception for some out of
422 # range integers
423 import sys
424 for endian in ('', '>', '<'):
425 for fmt in ('B', 'H', 'I', 'L'):
426 self.assertRaises((struct.error, OverflowError), struct.pack,
427 endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000428
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000429 self.assertRaises((struct.error, OverflowError), struct.pack,
430 endian + 'B', 300)
431 self.assertRaises((struct.error, OverflowError), struct.pack,
432 endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000433
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000434 self.assertRaises((struct.error, OverflowError), struct.pack,
435 endian + 'I', sys.maxsize * 4)
436 self.assertRaises((struct.error, OverflowError), struct.pack,
437 endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000438
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000439 def XXXtest_1530559(self):
440 # XXX This is broken: see the bug report
441 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
442 for endian in ('', '>', '<'):
443 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
444 self.check_float_coerce(endian + fmt, 1.0)
445 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000446
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000447 def test_unpack_from(self):
448 test_string = b'abcd01234'
449 fmt = '4s'
450 s = struct.Struct(fmt)
451 for cls in (bytes, bytearray):
452 data = cls(test_string)
453 if not isinstance(data, (bytes, bytearray)):
454 bytes_data = bytes(data, 'latin1')
455 else:
456 bytes_data = data
457 self.assertEqual(s.unpack_from(data), (b'abcd',))
458 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
459 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
460 for i in range(6):
461 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
462 for i in range(6, len(test_string) + 1):
463 self.assertRaises(struct.error, s.unpack_from, data, i)
464 for cls in (bytes, bytearray):
465 data = cls(test_string)
466 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
467 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
468 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
469 for i in range(6):
470 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
471 for i in range(6, len(test_string) + 1):
472 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000473
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000474 def test_pack_into(self):
475 test_string = b'Reykjavik rocks, eow!'
476 writable_buf = array.array('b', b' '*100)
477 fmt = '21s'
478 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000479
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000480 # Test without offset
481 s.pack_into(writable_buf, 0, test_string)
482 from_buf = writable_buf.tostring()[:len(test_string)]
483 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000484
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 # Test with offset.
486 s.pack_into(writable_buf, 10, test_string)
487 from_buf = writable_buf.tostring()[:len(test_string)+10]
488 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000489
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000490 # Go beyond boundaries.
491 small_buf = array.array('b', b' '*10)
492 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
493 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000494
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000495 # Test bogus offset (issue 3694)
496 sb = small_buf
497 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
498
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 def test_pack_into_fn(self):
500 test_string = b'Reykjavik rocks, eow!'
501 writable_buf = array.array('b', b' '*100)
502 fmt = '21s'
503 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 # Test without offset.
506 pack_into(writable_buf, 0, test_string)
507 from_buf = writable_buf.tostring()[:len(test_string)]
508 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000509
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000510 # Test with offset.
511 pack_into(writable_buf, 10, test_string)
512 from_buf = writable_buf.tostring()[:len(test_string)+10]
513 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000514
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000515 # Go beyond boundaries.
516 small_buf = array.array('b', b' '*10)
517 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
518 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000519
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000520 def test_unpack_with_buffer(self):
521 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
522 data1 = array.array('B', b'\x12\x34\x56\x78')
523 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
524 for data in [data1, data2]:
525 value, = struct.unpack('>I', data)
526 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000528 def test_bool(self):
529 for prefix in tuple("<>!=")+('',):
530 false = (), [], [], '', 0
531 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000532
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000533 falseFormat = prefix + '?' * len(false)
534 packedFalse = struct.pack(falseFormat, *false)
535 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000536
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000537 trueFormat = prefix + '?' * len(true)
538 packedTrue = struct.pack(trueFormat, *true)
539 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000540
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000541 self.assertEqual(len(true), len(unpackedTrue))
542 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000543
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000544 for t in unpackedFalse:
545 self.assertFalse(t)
546 for t in unpackedTrue:
547 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000548
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000549 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000550
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000551 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000552
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000553 if len(packed) != 1:
554 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
555 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000556
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000557 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
558 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000559
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000560 if IS32BIT:
561 def test_crasher(self):
562 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
563
564
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000565def test_main():
566 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000567
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000568if __name__ == '__main__':
569 test_main()