blob: 917f62695bc77653ab2e79050e0063087a44733f [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"
11del sys
Tim Peters17e17d42001-06-13 22:45:27 +000012
Thomas Wouters4d70c3d2006-06-08 14:42:34 +000013try:
14 import _struct
15except ImportError:
16 PY_STRUCT_RANGE_CHECKING = 0
17 PY_STRUCT_OVERFLOW_MASKING = 1
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)
21 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
22 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +000023
Tim Peters17e17d42001-06-13 22:45:27 +000024def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000025 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000026
27def bigendian_to_native(value):
28 if ISBIGENDIAN:
29 return value
30 else:
31 return string_reverse(value)
32
Thomas Wouters0e3f5912006-08-11 14:57:12 +000033def with_warning_restore(func):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000034 @wraps(func)
35 def decorator(*args, **kw):
36 with catch_warning():
Thomas Wouters902d6eb2007-01-09 23:18:33 +000037 # Grrr, we need this function to warn every time. Without removing
38 # the warningregistry, running test_tarfile then test_struct would fail
39 # on 64-bit platforms.
Neal Norwitz221085d2007-02-25 20:55:47 +000040 globals = func.__globals__
Thomas Wouters902d6eb2007-01-09 23:18:33 +000041 if '__warningregistry__' in globals:
42 del globals['__warningregistry__']
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 warnings.filterwarnings("error", category=DeprecationWarning)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000044 return func(*args, **kw)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000045 return decorator
Thomas Wouters0e3f5912006-08-11 14:57:12 +000046
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000047@with_warning_restore
Thomas Wouters0e3f5912006-08-11 14:57:12 +000048def deprecated_err(func, *args):
49 try:
50 func(*args)
51 except (struct.error, TypeError):
52 pass
53 except DeprecationWarning:
54 if not PY_STRUCT_OVERFLOW_MASKING:
Collin Winter3add4d72007-08-29 23:37:32 +000055 raise TestFailed("%s%s expected to raise struct.error" % (
56 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000057 else:
Collin Winter3add4d72007-08-29 23:37:32 +000058 raise TestFailed("%s%s did not raise error" % (
59 func.__name__, args))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000060
Tim Peters17e17d42001-06-13 22:45:27 +000061
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000063
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000064 @with_warning_restore
65 def check_float_coerce(self, format, number):
66 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
67 if PY_STRUCT_FLOAT_COERCE == 2:
68 # Test for pre-2.5 struct module
69 packed = struct.pack(format, number)
70 floored = struct.unpack(format, packed)[0]
71 self.assertEqual(floored, int(number),
72 "did not correcly coerce float to int")
73 return
74 try:
75 struct.pack(format, number)
76 except (struct.error, TypeError):
77 if PY_STRUCT_FLOAT_COERCE:
78 self.fail("expected DeprecationWarning for float coerce")
79 except DeprecationWarning:
80 if not PY_STRUCT_FLOAT_COERCE:
81 self.fail("expected to raise struct.error for float coerce")
Tim Peters17e17d42001-06-13 22:45:27 +000082 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000083 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000085 def test_isbigendian(self):
86 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000088 def test_consistence(self):
89 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000091 sz = struct.calcsize('i')
92 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000094 fmt = 'cbxxxxxxhhhhiillffd?'
95 fmt3 = '3c3b18x12h6i6l6f3d3?'
96 sz = struct.calcsize(fmt)
97 sz3 = struct.calcsize(fmt3)
98 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000099
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000100 self.assertRaises(struct.error, struct.pack, 'iii', 3)
101 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
102 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
103 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
104 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
105 s = struct.pack('ii', 1, 2)
106 self.assertRaises(struct.error, struct.unpack, 'iii', s)
107 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000108
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000109 def test_transitiveness(self):
110 c = b'a'
111 b = 1
112 h = 255
113 i = 65535
114 l = 65536
115 f = 3.1415
116 d = 3.1415
117 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000118
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000119 for prefix in ('', '@', '<', '>', '=', '!'):
120 for format in ('xcbhilfd?', 'xcBHILfd?'):
121 format = prefix + format
122 s = struct.pack(format, c, b, h, i, l, f, d, t)
123 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
124 self.assertEqual(cp, c)
125 self.assertEqual(bp, b)
126 self.assertEqual(hp, h)
127 self.assertEqual(ip, i)
128 self.assertEqual(lp, l)
129 self.assertEqual(int(100 * fp), int(100 * f))
130 self.assertEqual(int(100 * dp), int(100 * d))
131 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000132
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000133 def test_new_features(self):
134 # Test some of the new features in detail
135 # (format, argument, big-endian result, little-endian result, asymmetric)
136 tests = [
137 ('c', 'a', 'a', 'a', 0),
138 ('xc', 'a', '\0a', '\0a', 0),
139 ('cx', 'a', 'a\0', 'a\0', 0),
140 ('s', 'a', 'a', 'a', 0),
141 ('0s', 'helloworld', '', '', 1),
142 ('1s', 'helloworld', 'h', 'h', 1),
143 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
144 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
145 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
146 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
147 ('b', 7, '\7', '\7', 0),
148 ('b', -7, '\371', '\371', 0),
149 ('B', 7, '\7', '\7', 0),
150 ('B', 249, '\371', '\371', 0),
151 ('h', 700, '\002\274', '\274\002', 0),
152 ('h', -700, '\375D', 'D\375', 0),
153 ('H', 700, '\002\274', '\274\002', 0),
154 ('H', 0x10000-700, '\375D', 'D\375', 0),
155 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
156 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
157 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
158 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
159 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
160 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
161 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
162 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
163 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
164 ('d', 2.0, '@\000\000\000\000\000\000\000',
165 '\000\000\000\000\000\000\000@', 0),
166 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
167 ('d', -2.0, '\300\000\000\000\000\000\000\000',
168 '\000\000\000\000\000\000\000\300', 0),
169 ('?', 0, '\0', '\0', 0),
170 ('?', 3, '\1', '\1', 1),
171 ('?', True, '\1', '\1', 0),
172 ('?', [], '\0', '\0', 1),
173 ('?', (1,), '\1', '\1', 1),
174 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000175
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000176 for fmt, arg, big, lil, asy in tests:
177 big = bytes(big, "latin-1")
178 lil = bytes(lil, "latin-1")
179 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
180 ('='+fmt, ISBIGENDIAN and big or lil)]:
181 res = struct.pack(xfmt, arg)
182 self.assertEqual(res, exp)
183 self.assertEqual(struct.calcsize(xfmt), len(res))
184 rev = struct.unpack(xfmt, res)[0]
185 if isinstance(arg, str):
186 # Strings are returned as bytes since you can't know the
187 # encoding of the string when packed.
188 arg = bytes(arg, 'latin1')
189 if rev != arg:
190 self.assert_(asy)
191
192 def test_native_qQ(self):
193 # can't pack -1 as unsigned regardless
194 self.assertRaises((struct.error, TypeError), struct.pack, "Q", -1)
195 # can't pack string as 'q' regardless
196 self.assertRaises(struct.error, struct.pack, "q", "a")
197 # ditto, but 'Q'
198 self.assertRaises(struct.error, struct.pack, "Q", "a")
199
200 try:
201 struct.pack("q", 5)
202 except struct.error:
203 # does not have native q/Q
204 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000205 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000206 nbytes = struct.calcsize('q')
207 # The expected values here are in big-endian format, primarily
208 # because I'm on a little-endian machine and so this is the
209 # clearest way (for me) to force the code to get exercised.
210 for format, input, expected in (
211 ('q', -1, '\xff' * nbytes),
212 ('q', 0, '\x00' * nbytes),
213 ('Q', 0, '\x00' * nbytes),
214 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
215 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
216 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
217 expected = bytes(expected, "latin-1")
218 got = struct.pack(format, input)
219 native_expected = bigendian_to_native(expected)
220 self.assertEqual(got, native_expected)
221 retrieved = struct.unpack(format, got)[0]
222 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 def test_standard_integers(self):
225 # Standard integer tests (bBhHiIlLqQ).
226 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000229
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000230 # XXX Most std integer modes fail to test for out-of-range.
231 # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but
232 # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C
233 # reported by Mark Favas).
234 BUGGY_RANGE_CHECK = "bBhHiIlL"
Tim Peters17e17d42001-06-13 22:45:27 +0000235
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000236 def __init__(self, formatpair, bytesize):
237 self.assertEqual(len(formatpair), 2)
238 self.formatpair = formatpair
239 for direction in "<>!=":
240 for code in formatpair:
241 format = direction + code
242 self.assertEqual(struct.calcsize(format), bytesize)
243 self.bytesize = bytesize
244 self.bitsize = bytesize * 8
245 self.signed_code, self.unsigned_code = formatpair
246 self.unsigned_min = 0
247 self.unsigned_max = 2**self.bitsize - 1
248 self.signed_min = -(2**(self.bitsize-1))
249 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000250
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000251 def test_one(self, x, pack=struct.pack,
252 unpack=struct.unpack,
253 unhexlify=binascii.unhexlify):
254 # Try signed.
255 code = self.signed_code
256 if self.signed_min <= x <= self.signed_max:
257 # Try big-endian.
258 expected = x
259 if x < 0:
260 expected += 1 << self.bitsize
261 self.assert_(expected > 0)
262 expected = hex(expected)[2:] # chop "0x"
263 if len(expected) & 1:
264 expected = "0" + expected
265 expected = unhexlify(expected)
266 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000267
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268 # Pack work?
269 format = ">" + code
270 got = pack(format, x)
271 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000272
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000273 # Unpack work?
274 retrieved = unpack(format, got)[0]
275 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000276
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000277 # Adding any byte should cause a "too big" error.
278 self.assertRaises((struct.error, TypeError),
279 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000280
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000281 # Try little-endian.
282 format = "<" + code
283 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000284
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000285 # Pack work?
286 got = pack(format, x)
287 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000288
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000289 # Unpack work?
290 retrieved = unpack(format, got)[0]
291 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000292
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000293 # Adding any byte should cause a "too big" error.
294 self.assertRaises((struct.error, TypeError),
295 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000296
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000297 else:
298 # x is out of range -- verify pack realizes that.
299 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
300 if verbose:
301 print("Skipping buggy range check for code", code)
302 else:
303 deprecated_err(pack, ">" + code, x)
304 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000305
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000306 # Much the same for unsigned.
307 code = self.unsigned_code
308 if self.unsigned_min <= x <= self.unsigned_max:
309 # Try big-endian.
310 format = ">" + code
311 expected = x
312 expected = hex(expected)[2:] # chop "0x"
313 if len(expected) & 1:
314 expected = "0" + expected
315 expected = unhexlify(expected)
316 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000317
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000318 # Pack work?
319 got = pack(format, x)
320 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000321
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000322 # Unpack work?
323 retrieved = unpack(format, got)[0]
324 self.assertEqual(x, retrieved)
325
326 # Adding any byte should cause a "too big" error.
327 self.assertRaises((struct.error, TypeError),
328 unpack, format, b'\x01' + got)
329
330 # Try little-endian.
331 format = "<" + code
332 expected = string_reverse(expected)
333
334 # Pack work?
335 got = pack(format, x)
336 self.assertEqual(got, expected)
337
338 # Unpack work?
339 retrieved = unpack(format, got)[0]
340 self.assertEqual(x, retrieved)
341
342 # Adding any byte should cause a "too big" error.
343 self.assertRaises((struct.error, TypeError),
344 unpack, format, b'\x01' + got)
345
346 else:
347 # x is out of range -- verify pack realizes that.
348 if not PY_STRUCT_RANGE_CHECKING and code in self.BUGGY_RANGE_CHECK:
349 if verbose:
350 print("Skipping buggy range check for code", code)
351 else:
352 deprecated_err(pack, ">" + code, x)
353 deprecated_err(pack, "<" + code, x)
354
355 def run(self):
356 from random import randrange
357
358 # Create all interesting powers of 2.
359 values = []
360 for exp in range(self.bitsize + 3):
361 values.append(1 << exp)
362
363 # Add some random values.
364 for i in range(self.bitsize):
365 val = 0
366 for j in range(self.bytesize):
367 val = (val << 8) | randrange(256)
368 values.append(val)
369
370 # Try all those, and their negations, and +-1 from them. Note
371 # that this tests all power-of-2 boundaries in range, and a few out
372 # of range, plus +-(2**n +- 1).
373 for base in values:
374 for val in -base, base:
375 for incr in -1, 0, 1:
376 x = val + incr
377 try:
378 x = int(x)
379 except OverflowError:
380 pass
381 self.test_one(x)
382
383 # Some error cases.
384 for direction in "<>":
385 for code in self.formatpair:
386 for badobject in "a string", 3+42j, randrange:
387 self.assertRaises((struct.error, TypeError),
388 struct.pack, direction + code,
389 badobject)
390
391 for args in [("bB", 1),
392 ("hH", 2),
393 ("iI", 4),
394 ("lL", 4),
395 ("qQ", 8)]:
396 t = IntTester(*args)
397 t.run()
398
399 def test_p_code(self):
400 # Test p ("Pascal string") code.
401 for code, input, expected, expectedback in [
402 ('p','abc', '\x00', b''),
403 ('1p', 'abc', '\x00', b''),
404 ('2p', 'abc', '\x01a', b'a'),
405 ('3p', 'abc', '\x02ab', b'ab'),
406 ('4p', 'abc', '\x03abc', b'abc'),
407 ('5p', 'abc', '\x03abc\x00', b'abc'),
408 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
409 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
410 expected = bytes(expected, "latin-1")
411 got = struct.pack(code, input)
412 self.assertEqual(got, expected)
413 (got,) = struct.unpack(code, got)
414 self.assertEqual(got, expectedback)
415
416 def test_705836(self):
417 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
418 # from the low-order discarded bits could propagate into the exponent
419 # field, causing the result to be wrong by a factor of 2.
420 import math
421
422 for base in range(1, 33):
423 # smaller <- largest representable float less than base.
424 delta = 0.5
425 while base - delta / 2.0 != base:
426 delta /= 2.0
427 smaller = base - delta
428 # Packing this rounds away a solid string of trailing 1 bits.
429 packed = struct.pack("<f", smaller)
430 unpacked = struct.unpack("<f", packed)[0]
431 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
432 # 16, respectively.
433 self.assertEqual(base, unpacked)
434 bigpacked = struct.pack(">f", smaller)
435 self.assertEqual(bigpacked, string_reverse(packed))
436 unpacked = struct.unpack(">f", bigpacked)[0]
437 self.assertEqual(base, unpacked)
438
439 # Largest finite IEEE single.
440 big = (1 << 24) - 1
441 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000442 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000443 unpacked = struct.unpack(">f", packed)[0]
444 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000445
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000446 # The same, but tack on a 1 bit so it rounds up to infinity.
447 big = (1 << 25) - 1
448 big = math.ldexp(big, 127 - 24)
449 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000450
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000451 if PY_STRUCT_RANGE_CHECKING:
452 def test_1229380(self):
453 # SF bug 1229380. No struct.pack exception for some out of
454 # range integers
455 import sys
456 for endian in ('', '>', '<'):
457 for fmt in ('B', 'H', 'I', 'L'):
458 deprecated_err(struct.pack, endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000459
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000460 deprecated_err(struct.pack, endian + 'B', 300)
461 deprecated_err(struct.pack, endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000463 deprecated_err(struct.pack, endian + 'I', sys.maxsize * 4)
464 deprecated_err(struct.pack, endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 def XXXtest_1530559(self):
467 # XXX This is broken: see the bug report
468 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
469 for endian in ('', '>', '<'):
470 for fmt in ('B', 'H', 'I', 'L', 'b', 'h', 'i', 'l'):
471 self.check_float_coerce(endian + fmt, 1.0)
472 self.check_float_coerce(endian + fmt, 1.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000473
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000474 def test_unpack_from(self):
475 test_string = b'abcd01234'
476 fmt = '4s'
477 s = struct.Struct(fmt)
478 for cls in (bytes, bytearray):
479 data = cls(test_string)
480 if not isinstance(data, (bytes, bytearray)):
481 bytes_data = bytes(data, 'latin1')
482 else:
483 bytes_data = data
484 self.assertEqual(s.unpack_from(data), (b'abcd',))
485 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
486 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
487 for i in range(6):
488 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
489 for i in range(6, len(test_string) + 1):
490 self.assertRaises(struct.error, s.unpack_from, data, i)
491 for cls in (bytes, bytearray):
492 data = cls(test_string)
493 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
494 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
495 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
496 for i in range(6):
497 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
498 for i in range(6, len(test_string) + 1):
499 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000501 def test_pack_into(self):
502 test_string = b'Reykjavik rocks, eow!'
503 writable_buf = array.array('b', b' '*100)
504 fmt = '21s'
505 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 # Test without offset
508 s.pack_into(writable_buf, 0, test_string)
509 from_buf = writable_buf.tostring()[:len(test_string)]
510 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 # Test with offset.
513 s.pack_into(writable_buf, 10, test_string)
514 from_buf = writable_buf.tostring()[:len(test_string)+10]
515 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000516
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000517 # Go beyond boundaries.
518 small_buf = array.array('b', b' '*10)
519 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
520 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000521
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000522 def test_pack_into_fn(self):
523 test_string = b'Reykjavik rocks, eow!'
524 writable_buf = array.array('b', b' '*100)
525 fmt = '21s'
526 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000528 # Test without offset.
529 pack_into(writable_buf, 0, test_string)
530 from_buf = writable_buf.tostring()[:len(test_string)]
531 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000532
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000533 # Test with offset.
534 pack_into(writable_buf, 10, test_string)
535 from_buf = writable_buf.tostring()[:len(test_string)+10]
536 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000537
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000538 # Go beyond boundaries.
539 small_buf = array.array('b', b' '*10)
540 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
541 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000542
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000543 def test_unpack_with_buffer(self):
544 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
545 data1 = array.array('B', b'\x12\x34\x56\x78')
546 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
547 for data in [data1, data2]:
548 value, = struct.unpack('>I', data)
549 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000550
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000551 def test_bool(self):
552 for prefix in tuple("<>!=")+('',):
553 false = (), [], [], '', 0
554 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000555
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000556 falseFormat = prefix + '?' * len(false)
557 packedFalse = struct.pack(falseFormat, *false)
558 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000559
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000560 trueFormat = prefix + '?' * len(true)
561 packedTrue = struct.pack(trueFormat, *true)
562 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000563
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000564 self.assertEqual(len(true), len(unpackedTrue))
565 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000566
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000567 for t in unpackedFalse:
568 self.assertFalse(t)
569 for t in unpackedTrue:
570 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000571
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000572 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000573
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000574 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000575
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000576 if len(packed) != 1:
577 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
578 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000579
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000580 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
581 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000582
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000583def test_main():
584 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000585
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000586if __name__ == '__main__':
587 test_main()