blob: 6dc0e8dc05d5103fa4b3e9da577ff722839bf960 [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
7from test.support import TestFailed, verbose, run_unittest, catch_warning
8
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
18 PY_STRUCT_OVERFLOW_MASKING = 1
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019 PY_STRUCT_FLOAT_COERCE = 2
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000020else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
22 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
23 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000024
Tim Peters17e17d42001-06-13 22:45:27 +000025def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000026 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000027
28def bigendian_to_native(value):
29 if ISBIGENDIAN:
30 return value
31 else:
32 return string_reverse(value)
33
Thomas Wouters0e3f5912006-08-11 14:57:12 +000034def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000035 @wraps(func)
36 def decorator(*args, **kw):
37 with catch_warning():
Nick Coghlanb1304932008-07-13 12:25:08 +000038 # We need this function to warn every time, so stick an
39 # unqualifed 'always' at the head of the filter list
40 warnings.simplefilter("always")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000041 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000042 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000044
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000045@with_warning_restore
Thomas Wouters0e3f5912006-08-11 14:57:12 +000046def deprecated_err(func, *args):
47 try:
48 func(*args)
49 except (struct.error, TypeError):
50 pass
51 except DeprecationWarning:
52 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlanb1304932008-07-13 12:25:08 +000053 raise TestFailed("%s%s expected to raise DeprecationWarning" % (
Collin Winter3add4d72007-08-29 23:37:32 +000054 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000055 else:
Collin Winter3add4d72007-08-29 23:37:32 +000056 raise TestFailed("%s%s did not raise error" % (
57 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000058
Tim Peters17e17d42001-06-13 22:45:27 +000059
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000060class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000061
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062 @with_warning_restore
63 def check_float_coerce(self, format, number):
64 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
65 if PY_STRUCT_FLOAT_COERCE == 2:
66 # Test for pre-2.5 struct module
67 packed = struct.pack(format, number)
68 floored = struct.unpack(format, packed)[0]
69 self.assertEqual(floored, int(number),
70 "did not correcly coerce float to int")
71 return
72 try:
73 struct.pack(format, number)
74 except (struct.error, TypeError):
75 if PY_STRUCT_FLOAT_COERCE:
76 self.fail("expected DeprecationWarning for float coerce")
77 except DeprecationWarning:
78 if not PY_STRUCT_FLOAT_COERCE:
79 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000080 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000081 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000082
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000083 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000084 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000085
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000086 def test_consistence(self):
87 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000089 sz = struct.calcsize('i')
90 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000091
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000092 fmt = 'cbxxxxxxhhhhiillffd?'
93 fmt3 = '3c3b18x12h6i6l6f3d3?'
94 sz = struct.calcsize(fmt)
95 sz3 = struct.calcsize(fmt3)
96 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000097
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000098 self.assertRaises(struct.error, struct.pack, 'iii', 3)
99 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
100 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
101 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
102 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
103 s = struct.pack('ii', 1, 2)
104 self.assertRaises(struct.error, struct.unpack, 'iii', s)
105 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000106
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000107 def test_transitiveness(self):
108 c = b'a'
109 b = 1
110 h = 255
111 i = 65535
112 l = 65536
113 f = 3.1415
114 d = 3.1415
115 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000116
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000117 for prefix in ('', '@', '<', '>', '=', '!'):
118 for format in ('xcbhilfd?', 'xcBHILfd?'):
119 format = prefix + format
120 s = struct.pack(format, c, b, h, i, l, f, d, t)
121 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
122 self.assertEqual(cp, c)
123 self.assertEqual(bp, b)
124 self.assertEqual(hp, h)
125 self.assertEqual(ip, i)
126 self.assertEqual(lp, l)
127 self.assertEqual(int(100 * fp), int(100 * f))
128 self.assertEqual(int(100 * dp), int(100 * d))
129 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000130
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000131 def test_new_features(self):
132 # Test some of the new features in detail
133 # (format, argument, big-endian result, little-endian result, asymmetric)
134 tests = [
135 ('c', 'a', 'a', 'a', 0),
136 ('xc', 'a', '\0a', '\0a', 0),
137 ('cx', 'a', 'a\0', 'a\0', 0),
138 ('s', 'a', 'a', 'a', 0),
139 ('0s', 'helloworld', '', '', 1),
140 ('1s', 'helloworld', 'h', 'h', 1),
141 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
142 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
143 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
144 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
145 ('b', 7, '\7', '\7', 0),
146 ('b', -7, '\371', '\371', 0),
147 ('B', 7, '\7', '\7', 0),
148 ('B', 249, '\371', '\371', 0),
149 ('h', 700, '\002\274', '\274\002', 0),
150 ('h', -700, '\375D', 'D\375', 0),
151 ('H', 700, '\002\274', '\274\002', 0),
152 ('H', 0x10000-700, '\375D', 'D\375', 0),
153 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
154 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
155 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
156 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
158 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
159 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
160 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
161 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
162 ('d', 2.0, '@\000\000\000\000\000\000\000',
163 '\000\000\000\000\000\000\000@', 0),
164 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
165 ('d', -2.0, '\300\000\000\000\000\000\000\000',
166 '\000\000\000\000\000\000\000\300', 0),
167 ('?', 0, '\0', '\0', 0),
168 ('?', 3, '\1', '\1', 1),
169 ('?', True, '\1', '\1', 0),
170 ('?', [], '\0', '\0', 1),
171 ('?', (1,), '\1', '\1', 1),
172 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000173
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000174 for fmt, arg, big, lil, asy in tests:
175 big = bytes(big, "latin-1")
176 lil = bytes(lil, "latin-1")
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 isinstance(arg, str):
184 # Strings are returned as bytes since you can't know the
185 # encoding of the string when packed.
186 arg = bytes(arg, 'latin1')
187 if rev != arg:
188 self.assert_(asy)
189
190 def test_native_qQ(self):
191 # can't pack -1 as unsigned regardless
192 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
193 # can't pack string as 'q' regardless
194 self.assertRaises(struct.error, struct.pack, "q", "a")
195 # ditto, but 'Q'
196 self.assertRaises(struct.error, struct.pack, "Q", "a")
197
198 try:
199 struct.pack("q", 5)
200 except struct.error:
201 # does not have native q/Q
202 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000203 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000204 nbytes = struct.calcsize('q')
205 # The expected values here are in big-endian format, primarily
206 # because I'm on a little-endian machine and so this is the
207 # clearest way (for me) to force the code to get exercised.
208 for format, input, expected in (
209 ('q', -1, '\xff' * nbytes),
210 ('q', 0, '\x00' * nbytes),
211 ('Q', 0, '\x00' * nbytes),
212 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
213 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
214 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
215 expected = bytes(expected, "latin-1")
216 got = struct.pack(format, input)
217 native_expected = bigendian_to_native(expected)
218 self.assertEqual(got, native_expected)
219 retrieved = struct.unpack(format, got)[0]
220 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000221
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000222 def test_standard_integers(self):
223 # Standard integer tests (bBhHiIlLqQ).
224 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000225
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000226 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 # XXX Most std integer modes fail to test for out-of-range.
229 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
230 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
231 # reported by Mark Favas).
232 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000233
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000234 def __init__(self, formatpair, bytesize):
235 self.assertEqual(len(formatpair), 2)
236 self.formatpair = formatpair
237 for direction in "<>!=":
238 for code in formatpair:
239 format = direction + code
240 self.assertEqual(struct.calcsize(format), bytesize)
241 self.bytesize = bytesize
242 self.bitsize = bytesize * 8
243 self.signed_code, self.unsigned_code = formatpair
244 self.unsigned_min = 0
245 self.unsigned_max = 2**self.bitsize - 1
246 self.signed_min = -(2**(self.bitsize-1))
247 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000248
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000249 def test_one(self, x, pack=struct.pack,
250 unpack=struct.unpack,
251 unhexlify=binascii.unhexlify):
252 # Try signed.
253 code = self.signed_code
254 if self.signed_min <= x <= self.signed_max:
255 # Try big-endian.
256 expected = x
257 if x < 0:
258 expected += 1 << self.bitsize
259 self.assert_(expected > 0)
260 expected = hex(expected)[2:] # chop "0x"
261 if len(expected) & 1:
262 expected = "0" + expected
263 expected = unhexlify(expected)
264 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000265
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000266 # Pack work?
267 format = ">" + code
268 got = pack(format, x)
269 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000270
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000271 # Unpack work?
272 retrieved = unpack(format, got)[0]
273 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000274
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000275 # Adding any byte should cause a "too big" error.
276 self.assertRaises((struct.error, TypeError),
277 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000278
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000279 # Try little-endian.
280 format = "<" + code
281 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000282
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000283 # Pack work?
284 got = pack(format, x)
285 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000286
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000287 # Unpack work?
288 retrieved = unpack(format, got)[0]
289 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000290
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000291 # Adding any byte should cause a "too big" error.
292 self.assertRaises((struct.error, TypeError),
293 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000294
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000295 else:
296 # x is out of range -- verify pack realizes that.
297 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
298 if verbose:
299 print("Skipping buggy range check for code", code)
300 else:
301 deprecated_err(pack, ">" + code, x)
302 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000303
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000304 # Much the same for unsigned.
305 code = self.unsigned_code
306 if self.unsigned_min <= x <= self.unsigned_max:
307 # Try big-endian.
308 format = ">" + code
309 expected = x
310 expected = hex(expected)[2:] # chop "0x"
311 if len(expected) & 1:
312 expected = "0" + expected
313 expected = unhexlify(expected)
314 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000315
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000316 # Pack work?
317 got = pack(format, x)
318 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000319
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000320 # Unpack work?
321 retrieved = unpack(format, got)[0]
322 self.assertEqual(x, retrieved)
323
324 # Adding any byte should cause a "too big" error.
325 self.assertRaises((struct.error, TypeError),
326 unpack, format, b'\x01' + got)
327
328 # Try little-endian.
329 format = "<" + code
330 expected = string_reverse(expected)
331
332 # Pack work?
333 got = pack(format, x)
334 self.assertEqual(got, expected)
335
336 # Unpack work?
337 retrieved = unpack(format, got)[0]
338 self.assertEqual(x, retrieved)
339
340 # Adding any byte should cause a "too big" error.
341 self.assertRaises((struct.error, TypeError),
342 unpack, format, b'\x01' + got)
343
344 else:
345 # x is out of range -- verify pack realizes that.
346 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
347 if verbose:
348 print("Skipping buggy range check for code", code)
349 else:
350 deprecated_err(pack, ">" + code, x)
351 deprecated_err(pack, "<" + code, x)
352
353 def run(self):
354 from random import randrange
355
356 # Create all interesting powers of 2.
357 values = []
358 for exp in range(self.bitsize + 3):
359 values.append(1 << exp)
360
361 # Add some random values.
362 for i in range(self.bitsize):
363 val = 0
364 for j in range(self.bytesize):
365 val = (val << 8) | randrange(256)
366 values.append(val)
367
368 # Try all those, and their negations, and +-1 from them. Note
369 # that this tests all power-of-2 boundaries in range, and a few out
370 # of range, plus +-(2**n +- 1).
371 for base in values:
372 for val in -base, base:
373 for incr in -1, 0, 1:
374 x = val + incr
375 try:
376 x = int(x)
377 except OverflowError:
378 pass
379 self.test_one(x)
380
381 # Some error cases.
382 for direction in "<>":
383 for code in self.formatpair:
384 for badobject in "a string", 3+42j, randrange:
385 self.assertRaises((struct.error, TypeError),
386 struct.pack, direction + code,
387 badobject)
388
389 for args in [("bB", 1),
390 ("hH", 2),
391 ("iI", 4),
392 ("lL", 4),
393 ("qQ", 8)]:
394 t = IntTester(*args)
395 t.run()
396
397 def test_p_code(self):
398 # Test p ("Pascal string") code.
399 for code, input, expected, expectedback in [
400 ('p','abc', '\x00', b''),
401 ('1p', 'abc', '\x00', b''),
402 ('2p', 'abc', '\x01a', b'a'),
403 ('3p', 'abc', '\x02ab', b'ab'),
404 ('4p', 'abc', '\x03abc', b'abc'),
405 ('5p', 'abc', '\x03abc\x00', b'abc'),
406 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
407 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
408 expected = bytes(expected, "latin-1")
409 got = struct.pack(code, input)
410 self.assertEqual(got, expected)
411 (got,) = struct.unpack(code, got)
412 self.assertEqual(got, expectedback)
413
414 def test_705836(self):
415 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
416 # from the low-order discarded bits could propagate into the exponent
417 # field, causing the result to be wrong by a factor of 2.
418 import math
419
420 for base in range(1, 33):
421 # smaller <- largest representable float less than base.
422 delta = 0.5
423 while base - delta / 2.0 != base:
424 delta /= 2.0
425 smaller = base - delta
426 # Packing this rounds away a solid string of trailing 1 bits.
427 packed = struct.pack("<f", smaller)
428 unpacked = struct.unpack("<f", packed)[0]
429 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
430 # 16, respectively.
431 self.assertEqual(base, unpacked)
432 bigpacked = struct.pack(">f", smaller)
433 self.assertEqual(bigpacked, string_reverse(packed))
434 unpacked = struct.unpack(">f", bigpacked)[0]
435 self.assertEqual(base, unpacked)
436
437 # Largest finite IEEE single.
438 big = (1 << 24) - 1
439 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000440 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000441 unpacked = struct.unpack(">f", packed)[0]
442 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000443
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000444 # The same, but tack on a 1 bit so it rounds up to infinity.
445 big = (1 << 25) - 1
446 big = math.ldexp(big, 127 - 24)
447 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000448
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000449 if PY_STRUCT_RANGE_CHECKING:
450 def test_1229380(self):
451 # SF bug 1229380. No struct.pack exception for some out of
452 # range integers
453 import sys
454 for endian in ('', '>', '<'):
455 for fmt in ('B', 'H', 'I', 'L'):
456 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000457
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000458 deprecated_err(struct.pack, endian + 'B', 300)
459 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 deprecated_err(struct.pack, endian + 'I', sys.maxsize * 4)
462 deprecated_err(struct.pack, endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 def XXXtest_1530559(self):
465 # XXX This is broken: see the bug report
466 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
467 for endian in ('', '>', '<'):
468 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
469 self.check_float_coerce(endian + fmt, 1.0)
470 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000471
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000472 def test_unpack_from(self):
473 test_string = b'abcd01234'
474 fmt = '4s'
475 s = struct.Struct(fmt)
476 for cls in (bytes, bytearray):
477 data = cls(test_string)
478 if not isinstance(data, (bytes, bytearray)):
479 bytes_data = bytes(data, 'latin1')
480 else:
481 bytes_data = data
482 self.assertEqual(s.unpack_from(data), (b'abcd',))
483 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
484 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
485 for i in range(6):
486 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
487 for i in range(6, len(test_string) + 1):
488 self.assertRaises(struct.error, s.unpack_from, data, i)
489 for cls in (bytes, bytearray):
490 data = cls(test_string)
491 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
492 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
493 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
494 for i in range(6):
495 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
496 for i in range(6, len(test_string) + 1):
497 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000498
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 def test_pack_into(self):
500 test_string = b'Reykjavik rocks, eow!'
501 writable_buf = array.array('b', b' '*100)
502 fmt = '21s'
503 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 # Test without offset
506 s.pack_into(writable_buf, 0, test_string)
507 from_buf = writable_buf.tostring()[:len(test_string)]
508 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000509
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000510 # Test with offset.
511 s.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 Wouters0e3f5912006-08-11 14:57:12 +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, s.pack_into, small_buf, 0, test_string)
518 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000519
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000520 def test_pack_into_fn(self):
521 test_string = b'Reykjavik rocks, eow!'
522 writable_buf = array.array('b', b' '*100)
523 fmt = '21s'
524 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000525
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000526 # Test without offset.
527 pack_into(writable_buf, 0, test_string)
528 from_buf = writable_buf.tostring()[:len(test_string)]
529 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000530
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000531 # Test with offset.
532 pack_into(writable_buf, 10, test_string)
533 from_buf = writable_buf.tostring()[:len(test_string)+10]
534 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000535
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000536 # Go beyond boundaries.
537 small_buf = array.array('b', b' '*10)
538 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
539 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000540
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000541 def test_unpack_with_buffer(self):
542 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
543 data1 = array.array('B', b'\x12\x34\x56\x78')
544 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
545 for data in [data1, data2]:
546 value, = struct.unpack('>I', data)
547 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000548
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000549 def test_bool(self):
550 for prefix in tuple("<>!=")+('',):
551 false = (), [], [], '', 0
552 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000553
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000554 falseFormat = prefix + '?' * len(false)
555 packedFalse = struct.pack(falseFormat, *false)
556 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000557
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000558 trueFormat = prefix + '?' * len(true)
559 packedTrue = struct.pack(trueFormat, *true)
560 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000561
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000562 self.assertEqual(len(true), len(unpackedTrue))
563 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000564
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000565 for t in unpackedFalse:
566 self.assertFalse(t)
567 for t in unpackedTrue:
568 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000569
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000570 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000571
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000572 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000573
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000574 if len(packed) != 1:
575 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
576 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000577
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000578 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
579 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000580
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000581 if IS32BIT:
582 def test_crasher(self):
583 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
584
585
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000586def test_main():
587 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000588
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000589if __name__ == '__main__':
590 test_main()