blob: 1d10b8f0c26e2030b341936c087d85b0d0fceddf [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:
17 PY_STRUCT_RANGE_CHECKING = 0
Thomas Wouters0e3f5912006-08-11 14:57:12 +000018 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000019else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000022
Tim Peters17e17d42001-06-13 22:45:27 +000023def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000024 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000025
26def bigendian_to_native(value):
27 if ISBIGENDIAN:
28 return value
29 else:
30 return string_reverse(value)
31
Thomas Wouters0e3f5912006-08-11 14:57:12 +000032def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000033 @wraps(func)
34 def decorator(*args, **kw):
Brett Cannon1cd02472008-09-09 01:52:27 +000035 with warnings.catch_warnings():
Nick Coghlanb1304932008-07-13 12:25:08 +000036 # We need this function to warn every time, so stick an
37 # unqualifed 'always' at the head of the filter list
38 warnings.simplefilter("always")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000040 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000041 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000042
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043@with_warning_restore
Thomas Wouters0e3f5912006-08-11 14:57:12 +000044def deprecated_err(func, *args):
45 try:
46 func(*args)
Mark Dickinson21776072009-02-10 16:13:25 +000047 except (struct.error, OverflowError):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000048 pass
49 except DeprecationWarning:
Mark Dickinsonae681df2009-03-21 10:26:31 +000050 raise TestFailed("%s%s expected to raise DeprecationWarning" % (
Collin Winter3add4d72007-08-29 23:37:32 +000051 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000052 else:
Collin Winter3add4d72007-08-29 23:37:32 +000053 raise TestFailed("%s%s did not raise error" % (
54 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000055
Tim Peters17e17d42001-06-13 22:45:27 +000056
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000057class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000058
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000059 @with_warning_restore
60 def check_float_coerce(self, format, number):
61 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
62 if PY_STRUCT_FLOAT_COERCE == 2:
63 # Test for pre-2.5 struct module
64 packed = struct.pack(format, number)
65 floored = struct.unpack(format, packed)[0]
66 self.assertEqual(floored, int(number),
67 "did not correcly coerce float to int")
68 return
69 try:
70 struct.pack(format, number)
71 except (struct.error, TypeError):
72 if PY_STRUCT_FLOAT_COERCE:
73 self.fail("expected DeprecationWarning for float coerce")
74 except DeprecationWarning:
75 if not PY_STRUCT_FLOAT_COERCE:
76 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000077 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000078 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000079
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000080 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000081 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000082
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000083 def test_consistence(self):
84 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000085
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000086 sz = struct.calcsize('i')
87 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000089 fmt = 'cbxxxxxxhhhhiillffd?'
90 fmt3 = '3c3b18x12h6i6l6f3d3?'
91 sz = struct.calcsize(fmt)
92 sz3 = struct.calcsize(fmt3)
93 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000094
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000095 self.assertRaises(struct.error, struct.pack, 'iii', 3)
96 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
97 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
98 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
99 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
100 s = struct.pack('ii', 1, 2)
101 self.assertRaises(struct.error, struct.unpack, 'iii', s)
102 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000103
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000104 def test_transitiveness(self):
105 c = b'a'
106 b = 1
107 h = 255
108 i = 65535
109 l = 65536
110 f = 3.1415
111 d = 3.1415
112 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000113
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000114 for prefix in ('', '@', '<', '>', '=', '!'):
115 for format in ('xcbhilfd?', 'xcBHILfd?'):
116 format = prefix + format
117 s = struct.pack(format, c, b, h, i, l, f, d, t)
118 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
119 self.assertEqual(cp, c)
120 self.assertEqual(bp, b)
121 self.assertEqual(hp, h)
122 self.assertEqual(ip, i)
123 self.assertEqual(lp, l)
124 self.assertEqual(int(100 * fp), int(100 * f))
125 self.assertEqual(int(100 * dp), int(100 * d))
126 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000127
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000128 def test_new_features(self):
129 # Test some of the new features in detail
130 # (format, argument, big-endian result, little-endian result, asymmetric)
131 tests = [
132 ('c', 'a', 'a', 'a', 0),
133 ('xc', 'a', '\0a', '\0a', 0),
134 ('cx', 'a', 'a\0', 'a\0', 0),
135 ('s', 'a', 'a', 'a', 0),
136 ('0s', 'helloworld', '', '', 1),
137 ('1s', 'helloworld', 'h', 'h', 1),
138 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
139 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
140 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
141 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
142 ('b', 7, '\7', '\7', 0),
143 ('b', -7, '\371', '\371', 0),
144 ('B', 7, '\7', '\7', 0),
145 ('B', 249, '\371', '\371', 0),
146 ('h', 700, '\002\274', '\274\002', 0),
147 ('h', -700, '\375D', 'D\375', 0),
148 ('H', 700, '\002\274', '\274\002', 0),
149 ('H', 0x10000-700, '\375D', 'D\375', 0),
150 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
151 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
152 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
153 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
154 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
155 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
156 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
157 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
158 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
159 ('d', 2.0, '@\000\000\000\000\000\000\000',
160 '\000\000\000\000\000\000\000@', 0),
161 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
162 ('d', -2.0, '\300\000\000\000\000\000\000\000',
163 '\000\000\000\000\000\000\000\300', 0),
164 ('?', 0, '\0', '\0', 0),
165 ('?', 3, '\1', '\1', 1),
166 ('?', True, '\1', '\1', 0),
167 ('?', [], '\0', '\0', 1),
168 ('?', (1,), '\1', '\1', 1),
169 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000170
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000171 for fmt, arg, big, lil, asy in tests:
172 big = bytes(big, "latin-1")
173 lil = bytes(lil, "latin-1")
174 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
175 ('='+fmt, ISBIGENDIAN and big or lil)]:
176 res = struct.pack(xfmt, arg)
177 self.assertEqual(res, exp)
178 self.assertEqual(struct.calcsize(xfmt), len(res))
179 rev = struct.unpack(xfmt, res)[0]
180 if isinstance(arg, str):
181 # Strings are returned as bytes since you can't know the
182 # encoding of the string when packed.
183 arg = bytes(arg, 'latin1')
184 if rev != arg:
185 self.assert_(asy)
186
187 def test_native_qQ(self):
188 # can't pack -1 as unsigned regardless
Mark Dickinson21776072009-02-10 16:13:25 +0000189 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000190 # can't pack string as 'q' regardless
191 self.assertRaises(struct.error, struct.pack, "q", "a")
192 # ditto, but 'Q'
193 self.assertRaises(struct.error, struct.pack, "Q", "a")
194
195 try:
196 struct.pack("q", 5)
197 except struct.error:
198 # does not have native q/Q
199 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000200 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000201 nbytes = struct.calcsize('q')
202 # The expected values here are in big-endian format, primarily
203 # because I'm on a little-endian machine and so this is the
204 # clearest way (for me) to force the code to get exercised.
205 for format, input, expected in (
206 ('q', -1, '\xff' * nbytes),
207 ('q', 0, '\x00' * nbytes),
208 ('Q', 0, '\x00' * nbytes),
209 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
210 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
211 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
212 expected = bytes(expected, "latin-1")
213 got = struct.pack(format, input)
214 native_expected = bigendian_to_native(expected)
215 self.assertEqual(got, native_expected)
216 retrieved = struct.unpack(format, got)[0]
217 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000218
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000219 def test_standard_integers(self):
220 # Standard integer tests (bBhHiIlLqQ).
221 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000222
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000223 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000224
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000225 # XXX Most std integer modes fail to test for out-of-range.
226 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
227 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
228 # reported by Mark Favas).
229 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000230
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000231 def __init__(self, formatpair, bytesize):
232 self.assertEqual(len(formatpair), 2)
233 self.formatpair = formatpair
234 for direction in "<>!=":
235 for code in formatpair:
236 format = direction + code
237 self.assertEqual(struct.calcsize(format), bytesize)
238 self.bytesize = bytesize
239 self.bitsize = bytesize * 8
240 self.signed_code, self.unsigned_code = formatpair
241 self.unsigned_min = 0
242 self.unsigned_max = 2**self.bitsize - 1
243 self.signed_min = -(2**(self.bitsize-1))
244 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000245
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000246 def test_one(self, x, pack=struct.pack,
247 unpack=struct.unpack,
248 unhexlify=binascii.unhexlify):
249 # Try signed.
250 code = self.signed_code
251 if self.signed_min <= x <= self.signed_max:
252 # Try big-endian.
253 expected = x
254 if x < 0:
255 expected += 1 << self.bitsize
256 self.assert_(expected > 0)
257 expected = hex(expected)[2:] # chop "0x"
258 if len(expected) & 1:
259 expected = "0" + expected
260 expected = unhexlify(expected)
261 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000262
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000263 # Pack work?
264 format = ">" + code
265 got = pack(format, x)
266 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000267
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268 # Unpack work?
269 retrieved = unpack(format, got)[0]
270 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000271
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000272 # Adding any byte should cause a "too big" error.
273 self.assertRaises((struct.error, TypeError),
274 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000275
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000276 # Try little-endian.
277 format = "<" + code
278 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000279
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000280 # Pack work?
281 got = pack(format, x)
282 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000283
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000284 # Unpack work?
285 retrieved = unpack(format, got)[0]
286 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000287
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000288 # Adding any byte should cause a "too big" error.
289 self.assertRaises((struct.error, TypeError),
290 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000291
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000292 else:
293 # x is out of range -- verify pack realizes that.
294 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
295 if verbose:
296 print("Skipping buggy range check for code", code)
297 else:
298 deprecated_err(pack, ">" + code, x)
299 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000300
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000301 # Much the same for unsigned.
302 code = self.unsigned_code
303 if self.unsigned_min <= x <= self.unsigned_max:
304 # Try big-endian.
305 format = ">" + code
306 expected = x
307 expected = hex(expected)[2:] # chop "0x"
308 if len(expected) & 1:
309 expected = "0" + expected
310 expected = unhexlify(expected)
311 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000312
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000313 # Pack work?
314 got = pack(format, x)
315 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000316
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000317 # Unpack work?
318 retrieved = unpack(format, got)[0]
319 self.assertEqual(x, retrieved)
320
321 # Adding any byte should cause a "too big" error.
322 self.assertRaises((struct.error, TypeError),
323 unpack, format, b'\x01' + got)
324
325 # Try little-endian.
326 format = "<" + code
327 expected = string_reverse(expected)
328
329 # Pack work?
330 got = pack(format, x)
331 self.assertEqual(got, expected)
332
333 # Unpack work?
334 retrieved = unpack(format, got)[0]
335 self.assertEqual(x, retrieved)
336
337 # Adding any byte should cause a "too big" error.
338 self.assertRaises((struct.error, TypeError),
339 unpack, format, b'\x01' + got)
340
341 else:
342 # x is out of range -- verify pack realizes that.
343 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
344 if verbose:
345 print("Skipping buggy range check for code", code)
346 else:
347 deprecated_err(pack, ">" + code, x)
348 deprecated_err(pack, "<" + code, x)
349
350 def run(self):
351 from random import randrange
352
353 # Create all interesting powers of 2.
354 values = []
355 for exp in range(self.bitsize + 3):
356 values.append(1 << exp)
357
358 # Add some random values.
359 for i in range(self.bitsize):
360 val = 0
361 for j in range(self.bytesize):
362 val = (val << 8) | randrange(256)
363 values.append(val)
364
365 # Try all those, and their negations, and +-1 from them. Note
366 # that this tests all power-of-2 boundaries in range, and a few out
367 # of range, plus +-(2**n +- 1).
368 for base in values:
369 for val in -base, base:
370 for incr in -1, 0, 1:
371 x = val + incr
372 try:
373 x = int(x)
374 except OverflowError:
375 pass
376 self.test_one(x)
377
378 # Some error cases.
379 for direction in "<>":
380 for code in self.formatpair:
381 for badobject in "a string", 3+42j, randrange:
382 self.assertRaises((struct.error, TypeError),
383 struct.pack, direction + code,
384 badobject)
385
386 for args in [("bB", 1),
387 ("hH", 2),
388 ("iI", 4),
389 ("lL", 4),
390 ("qQ", 8)]:
391 t = IntTester(*args)
392 t.run()
393
394 def test_p_code(self):
395 # Test p ("Pascal string") code.
396 for code, input, expected, expectedback in [
397 ('p','abc', '\x00', b''),
398 ('1p', 'abc', '\x00', b''),
399 ('2p', 'abc', '\x01a', b'a'),
400 ('3p', 'abc', '\x02ab', b'ab'),
401 ('4p', 'abc', '\x03abc', b'abc'),
402 ('5p', 'abc', '\x03abc\x00', b'abc'),
403 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
404 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
405 expected = bytes(expected, "latin-1")
406 got = struct.pack(code, input)
407 self.assertEqual(got, expected)
408 (got,) = struct.unpack(code, got)
409 self.assertEqual(got, expectedback)
410
411 def test_705836(self):
412 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
413 # from the low-order discarded bits could propagate into the exponent
414 # field, causing the result to be wrong by a factor of 2.
415 import math
416
417 for base in range(1, 33):
418 # smaller <- largest representable float less than base.
419 delta = 0.5
420 while base - delta / 2.0 != base:
421 delta /= 2.0
422 smaller = base - delta
423 # Packing this rounds away a solid string of trailing 1 bits.
424 packed = struct.pack("<f", smaller)
425 unpacked = struct.unpack("<f", packed)[0]
426 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
427 # 16, respectively.
428 self.assertEqual(base, unpacked)
429 bigpacked = struct.pack(">f", smaller)
430 self.assertEqual(bigpacked, string_reverse(packed))
431 unpacked = struct.unpack(">f", bigpacked)[0]
432 self.assertEqual(base, unpacked)
433
434 # Largest finite IEEE single.
435 big = (1 << 24) - 1
436 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000437 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000438 unpacked = struct.unpack(">f", packed)[0]
439 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000440
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000441 # The same, but tack on a 1 bit so it rounds up to infinity.
442 big = (1 << 25) - 1
443 big = math.ldexp(big, 127 - 24)
444 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000445
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000446 if PY_STRUCT_RANGE_CHECKING:
447 def test_1229380(self):
448 # SF bug 1229380. No struct.pack exception for some out of
449 # range integers
450 import sys
451 for endian in ('', '>', '<'):
452 for fmt in ('B', 'H', 'I', 'L'):
453 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000454
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000455 deprecated_err(struct.pack, endian + 'B', 300)
456 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000457
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000458 deprecated_err(struct.pack, endian + 'I', sys.maxsize * 4)
459 deprecated_err(struct.pack, endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 def XXXtest_1530559(self):
462 # XXX This is broken: see the bug report
463 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
464 for endian in ('', '>', '<'):
465 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
466 self.check_float_coerce(endian + fmt, 1.0)
467 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000468
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000469 def test_unpack_from(self):
470 test_string = b'abcd01234'
471 fmt = '4s'
472 s = struct.Struct(fmt)
473 for cls in (bytes, bytearray):
474 data = cls(test_string)
475 if not isinstance(data, (bytes, bytearray)):
476 bytes_data = bytes(data, 'latin1')
477 else:
478 bytes_data = data
479 self.assertEqual(s.unpack_from(data), (b'abcd',))
480 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
481 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
482 for i in range(6):
483 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
484 for i in range(6, len(test_string) + 1):
485 self.assertRaises(struct.error, s.unpack_from, data, i)
486 for cls in (bytes, bytearray):
487 data = cls(test_string)
488 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
489 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
490 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
491 for i in range(6):
492 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
493 for i in range(6, len(test_string) + 1):
494 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000495
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000496 def test_pack_into(self):
497 test_string = b'Reykjavik rocks, eow!'
498 writable_buf = array.array('b', b' '*100)
499 fmt = '21s'
500 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 # Test without offset
503 s.pack_into(writable_buf, 0, test_string)
504 from_buf = writable_buf.tostring()[:len(test_string)]
505 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 # Test with offset.
508 s.pack_into(writable_buf, 10, test_string)
509 from_buf = writable_buf.tostring()[:len(test_string)+10]
510 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 # Go beyond boundaries.
513 small_buf = array.array('b', b' '*10)
514 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
515 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000516
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000517 # Test bogus offset (issue 3694)
518 sb = small_buf
519 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
520
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000521 def test_pack_into_fn(self):
522 test_string = b'Reykjavik rocks, eow!'
523 writable_buf = array.array('b', b' '*100)
524 fmt = '21s'
525 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000526
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000527 # Test without offset.
528 pack_into(writable_buf, 0, test_string)
529 from_buf = writable_buf.tostring()[:len(test_string)]
530 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000531
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000532 # Test with offset.
533 pack_into(writable_buf, 10, test_string)
534 from_buf = writable_buf.tostring()[:len(test_string)+10]
535 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000536
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000537 # Go beyond boundaries.
538 small_buf = array.array('b', b' '*10)
539 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
540 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000541
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000542 def test_unpack_with_buffer(self):
543 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
544 data1 = array.array('B', b'\x12\x34\x56\x78')
545 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
546 for data in [data1, data2]:
547 value, = struct.unpack('>I', data)
548 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000549
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000550 def test_bool(self):
551 for prefix in tuple("<>!=")+('',):
552 false = (), [], [], '', 0
553 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000554
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000555 falseFormat = prefix + '?' * len(false)
556 packedFalse = struct.pack(falseFormat, *false)
557 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000558
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000559 trueFormat = prefix + '?' * len(true)
560 packedTrue = struct.pack(trueFormat, *true)
561 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000562
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000563 self.assertEqual(len(true), len(unpackedTrue))
564 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000565
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000566 for t in unpackedFalse:
567 self.assertFalse(t)
568 for t in unpackedTrue:
569 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000570
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000571 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000572
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000573 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000574
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000575 if len(packed) != 1:
576 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
577 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000578
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000579 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
580 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000581
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000582 if IS32BIT:
583 def test_crasher(self):
584 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
585
586
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000587def test_main():
588 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000589
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000590if __name__ == '__main__':
591 test_main()