blob: 61f48d691a2f8d5d352d9c4d4f825e619b5d1614 [file] [log] [blame]
Martin Blais2856e5f2006-05-26 12:03:27 +00001import array
Benjamin Petersond5299862008-06-11 01:31:28 +00002import unittest
3import struct
Bob Ippolito2fd39772006-05-29 22:55:48 +00004import warnings
Georg Brandl6269fec2009-01-01 12:15:31 +00005warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
6 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00007
Benjamin Petersond5299862008-06-11 01:31:28 +00008from functools import wraps
Brett Cannon672237d2008-09-09 00:49:16 +00009from test.test_support import TestFailed, verbose, run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +000010
Tim Peters17e17d42001-06-13 22:45:27 +000011import sys
12ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000013IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000014del sys
Tim Peters17e17d42001-06-13 22:45:27 +000015
Bob Ippolito2fd39772006-05-29 22:55:48 +000016try:
17 import _struct
18except ImportError:
19 PY_STRUCT_RANGE_CHECKING = 0
Bob Ippolito4182a752006-05-30 17:37:54 +000020 PY_STRUCT_OVERFLOW_MASKING = 1
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000021 PY_STRUCT_FLOAT_COERCE = 2
Bob Ippolito2fd39772006-05-29 22:55:48 +000022else:
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000023 PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
24 PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
25 PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
Bob Ippolitoe27337b2006-05-26 13:15:44 +000026
Tim Peters17e17d42001-06-13 22:45:27 +000027def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000028 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000029
30def bigendian_to_native(value):
31 if ISBIGENDIAN:
32 return value
33 else:
34 return string_reverse(value)
35
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000036def with_warning_restore(func):
Benjamin Petersond5299862008-06-11 01:31:28 +000037 @wraps(func)
38 def decorator(*args, **kw):
Brett Cannon672237d2008-09-09 00:49:16 +000039 with warnings.catch_warnings():
Nick Coghlan38469e22008-07-13 12:23:47 +000040 # We need this function to warn every time, so stick an
41 # unqualifed 'always' at the head of the filter list
42 warnings.simplefilter("always")
Benjamin Petersond5299862008-06-11 01:31:28 +000043 warnings.filterwarnings("error", category=DeprecationWarning)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000044 return func(*args, **kw)
Benjamin Petersond5299862008-06-11 01:31:28 +000045 return decorator
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000046
Benjamin Petersond5299862008-06-11 01:31:28 +000047@with_warning_restore
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000048def deprecated_err(func, *args):
49 try:
50 func(*args)
Mark Dickinson4015f622009-02-10 15:46:50 +000051 except (struct.error, OverflowError):
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000052 pass
53 except DeprecationWarning:
54 if not PY_STRUCT_OVERFLOW_MASKING:
Nick Coghlan38469e22008-07-13 12:23:47 +000055 raise TestFailed, "%s%s expected to raise DeprecationWarning" % (
Bob Ippolito2fd39772006-05-29 22:55:48 +000056 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000057 else:
58 raise TestFailed, "%s%s did not raise error" % (
59 func.__name__, args)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +000060
Tim Peters17e17d42001-06-13 22:45:27 +000061
Benjamin Petersond5299862008-06-11 01:31:28 +000062class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000063
Benjamin Petersond5299862008-06-11 01:31:28 +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)
Mark Dickinson463dc4b2009-07-05 10:01:24 +000076 except struct.error:
Benjamin Petersond5299862008-06-11 01:31:28 +000077 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:
Benjamin Petersond5299862008-06-11 01:31:28 +000083 self.fail("did not raise error for float coerce")
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Benjamin Petersond5299862008-06-11 01:31:28 +000085 def test_isbigendian(self):
86 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000087
Benjamin Petersond5299862008-06-11 01:31:28 +000088 def test_consistence(self):
89 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Benjamin Petersond5299862008-06-11 01:31:28 +000091 sz = struct.calcsize('i')
92 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Benjamin Petersond5299862008-06-11 01:31:28 +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
Benjamin Petersond5299862008-06-11 01:31:28 +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', '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
Benjamin Petersond5299862008-06-11 01:31:28 +0000109 def test_transitiveness(self):
110 c = '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
Benjamin Petersond5299862008-06-11 01:31:28 +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
Benjamin Petersond5299862008-06-11 01:31:28 +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', 70000000L, '\004,\035\200', '\200\035,\004', 0),
158 ('I', 0x100000000L-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', 70000000L, '\004,\035\200', '\200\035,\004', 0),
162 ('L', 0x100000000L-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
Benjamin Petersond5299862008-06-11 01:31:28 +0000176 for fmt, arg, big, lil, asy in tests:
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 rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000184 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000185
186 def test_native_qQ(self):
187 # can't pack -1 as unsigned regardless
Mark Dickinson4015f622009-02-10 15:46:50 +0000188 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Benjamin Petersond5299862008-06-11 01:31:28 +0000189 # can't pack string as 'q' regardless
190 self.assertRaises(struct.error, struct.pack, "q", "a")
191 # ditto, but 'Q'
192 self.assertRaises(struct.error, struct.pack, "Q", "a")
193
194 try:
195 struct.pack("q", 5)
196 except struct.error:
197 # does not have native q/Q
198 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000199 else:
Benjamin Petersond5299862008-06-11 01:31:28 +0000200 bytes = struct.calcsize('q')
201 # The expected values here are in big-endian format, primarily
202 # because I'm on a little-endian machine and so this is the
203 # clearest way (for me) to force the code to get exercised.
204 for format, input, expected in (
205 ('q', -1, '\xff' * bytes),
206 ('q', 0, '\x00' * bytes),
207 ('Q', 0, '\x00' * bytes),
208 ('q', 1L, '\x00' * (bytes-1) + '\x01'),
209 ('Q', (1L << (8*bytes))-1, '\xff' * bytes),
210 ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))):
211 got = struct.pack(format, input)
212 native_expected = bigendian_to_native(expected)
213 self.assertEqual(got, native_expected)
214 retrieved = struct.unpack(format, got)[0]
215 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000216
Benjamin Petersond5299862008-06-11 01:31:28 +0000217 def test_standard_integers(self):
218 # Standard integer tests (bBhHiIlLqQ).
219 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000220
Benjamin Petersond5299862008-06-11 01:31:28 +0000221 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000222
Benjamin Petersond5299862008-06-11 01:31:28 +0000223 def __init__(self, formatpair, bytesize):
Gregory P. Smith28399852009-03-31 16:54:10 +0000224 super(IntTester, self).__init__(methodName='test_one')
Benjamin Petersond5299862008-06-11 01:31:28 +0000225 self.assertEqual(len(formatpair), 2)
226 self.formatpair = formatpair
227 for direction in "<>!=":
228 for code in formatpair:
229 format = direction + code
230 self.assertEqual(struct.calcsize(format), bytesize)
231 self.bytesize = bytesize
232 self.bitsize = bytesize * 8
233 self.signed_code, self.unsigned_code = formatpair
234 self.unsigned_min = 0
235 self.unsigned_max = 2L**self.bitsize - 1
236 self.signed_min = -(2L**(self.bitsize-1))
237 self.signed_max = 2L**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000238
Benjamin Petersond5299862008-06-11 01:31:28 +0000239 def test_one(self, x, pack=struct.pack,
240 unpack=struct.unpack,
241 unhexlify=binascii.unhexlify):
242 # Try signed.
243 code = self.signed_code
244 if self.signed_min <= x <= self.signed_max:
245 # Try big-endian.
246 expected = long(x)
247 if x < 0:
248 expected += 1L << self.bitsize
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000249 self.assertTrue(expected > 0)
Benjamin Petersond5299862008-06-11 01:31:28 +0000250 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
251 if len(expected) & 1:
252 expected = "0" + expected
253 expected = unhexlify(expected)
254 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000255
Benjamin Petersond5299862008-06-11 01:31:28 +0000256 # Pack work?
257 format = ">" + code
258 got = pack(format, x)
259 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000260
Benjamin Petersond5299862008-06-11 01:31:28 +0000261 # Unpack work?
262 retrieved = unpack(format, got)[0]
263 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000264
Benjamin Petersond5299862008-06-11 01:31:28 +0000265 # Adding any byte should cause a "too big" error.
266 self.assertRaises((struct.error, TypeError), unpack, format,
267 '\x01' + got)
268 # Try little-endian.
269 format = "<" + code
270 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000271
Benjamin Petersond5299862008-06-11 01:31:28 +0000272 # Pack work?
273 got = pack(format, x)
274 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000275
Benjamin Petersond5299862008-06-11 01:31:28 +0000276 # Unpack work?
277 retrieved = unpack(format, got)[0]
278 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000279
Benjamin Petersond5299862008-06-11 01:31:28 +0000280 # Adding any byte should cause a "too big" error.
281 self.assertRaises((struct.error, TypeError), unpack, format,
282 '\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000283
Benjamin Petersond5299862008-06-11 01:31:28 +0000284 else:
285 # x is out of range -- verify pack realizes that.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000286 deprecated_err(pack, ">" + code, x)
287 deprecated_err(pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000288
Benjamin Petersond5299862008-06-11 01:31:28 +0000289 # Much the same for unsigned.
290 code = self.unsigned_code
291 if self.unsigned_min <= x <= self.unsigned_max:
292 # Try big-endian.
293 format = ">" + code
294 expected = long(x)
295 expected = hex(expected)[2:-1] # chop "0x" and trailing 'L'
296 if len(expected) & 1:
297 expected = "0" + expected
298 expected = unhexlify(expected)
299 expected = "\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000300
Benjamin Petersond5299862008-06-11 01:31:28 +0000301 # Pack work?
302 got = pack(format, x)
303 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000304
Benjamin Petersond5299862008-06-11 01:31:28 +0000305 # Unpack work?
306 retrieved = unpack(format, got)[0]
307 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000308
Benjamin Petersond5299862008-06-11 01:31:28 +0000309 # Adding any byte should cause a "too big" error.
310 self.assertRaises((struct.error, TypeError), unpack, format,
311 '\x01' + got)
312
313 # Try little-endian.
314 format = "<" + code
315 expected = string_reverse(expected)
316
317 # Pack work?
318 got = pack(format, x)
319 self.assertEqual(got, expected)
320
321 # Unpack work?
322 retrieved = unpack(format, got)[0]
323 self.assertEqual(x, retrieved)
324
325 # Adding any byte should cause a "too big" error.
326 self.assertRaises((struct.error, TypeError), unpack, format,
327 '\x01' + got)
328
329 else:
330 # x is out of range -- verify pack realizes that.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000331 deprecated_err(pack, ">" + code, x)
332 deprecated_err(pack, "<" + code, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000333
334 def run(self):
335 from random import randrange
336
337 # Create all interesting powers of 2.
338 values = []
339 for exp in range(self.bitsize + 3):
340 values.append(1L << exp)
341
342 # Add some random values.
343 for i in range(self.bitsize):
344 val = 0L
345 for j in range(self.bytesize):
346 val = (val << 8) | randrange(256)
347 values.append(val)
348
349 # Try all those, and their negations, and +-1 from them. Note
350 # that this tests all power-of-2 boundaries in range, and a few out
351 # of range, plus +-(2**n +- 1).
352 for base in values:
353 for val in -base, base:
354 for incr in -1, 0, 1:
355 x = val + incr
356 try:
357 x = int(x)
358 except OverflowError:
359 pass
360 self.test_one(x)
361
362 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000363 class NotAnIntNS(object):
364 def __int__(self):
365 return 42
366
367 def __long__(self):
368 return 1729L
369
370 class NotAnIntOS:
371 def __int__(self):
372 return 10585
373
374 def __long__(self):
375 return -163L
376
Benjamin Petersond5299862008-06-11 01:31:28 +0000377 for direction in "<>":
378 for code in self.formatpair:
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000379 for badobject in ("a string", 3+42j, randrange,
380 NotAnIntNS(), NotAnIntOS()):
381 self.assertRaises(struct.error,
Benjamin Petersond5299862008-06-11 01:31:28 +0000382 struct.pack, direction + code,
383 badobject)
384
385 for args in [("bB", 1),
386 ("hH", 2),
387 ("iI", 4),
388 ("lL", 4),
389 ("qQ", 8)]:
390 t = IntTester(*args)
391 t.run()
392
393 def test_p_code(self):
394 # Test p ("Pascal string") code.
395 for code, input, expected, expectedback in [
396 ('p','abc', '\x00', ''),
397 ('1p', 'abc', '\x00', ''),
398 ('2p', 'abc', '\x01a', 'a'),
399 ('3p', 'abc', '\x02ab', 'ab'),
400 ('4p', 'abc', '\x03abc', 'abc'),
401 ('5p', 'abc', '\x03abc\x00', 'abc'),
402 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
403 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
404 got = struct.pack(code, input)
405 self.assertEqual(got, expected)
406 (got,) = struct.unpack(code, got)
407 self.assertEqual(got, expectedback)
408
409 def test_705836(self):
410 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
411 # from the low-order discarded bits could propagate into the exponent
412 # field, causing the result to be wrong by a factor of 2.
413 import math
414
415 for base in range(1, 33):
416 # smaller <- largest representable float less than base.
417 delta = 0.5
418 while base - delta / 2.0 != base:
419 delta /= 2.0
420 smaller = base - delta
421 # Packing this rounds away a solid string of trailing 1 bits.
422 packed = struct.pack("<f", smaller)
423 unpacked = struct.unpack("<f", packed)[0]
424 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
425 # 16, respectively.
426 self.assertEqual(base, unpacked)
427 bigpacked = struct.pack(">f", smaller)
428 self.assertEqual(bigpacked, string_reverse(packed))
429 unpacked = struct.unpack(">f", bigpacked)[0]
430 self.assertEqual(base, unpacked)
431
432 # Largest finite IEEE single.
433 big = (1 << 24) - 1
434 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000435 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000436 unpacked = struct.unpack(">f", packed)[0]
437 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000438
Benjamin Petersond5299862008-06-11 01:31:28 +0000439 # The same, but tack on a 1 bit so it rounds up to infinity.
440 big = (1 << 25) - 1
441 big = math.ldexp(big, 127 - 24)
442 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000443
Benjamin Petersond5299862008-06-11 01:31:28 +0000444 if PY_STRUCT_RANGE_CHECKING:
445 def test_1229380(self):
446 # SF bug 1229380. No struct.pack exception for some out of
447 # range integers
448 import sys
449 for endian in ('', '>', '<'):
450 for cls in (int, long):
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000451 for fmt in ('B', 'H', 'I', 'L', 'Q'):
Benjamin Petersond5299862008-06-11 01:31:28 +0000452 deprecated_err(struct.pack, endian + fmt, cls(-1))
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000453
Benjamin Petersond5299862008-06-11 01:31:28 +0000454 deprecated_err(struct.pack, endian + 'B', cls(300))
455 deprecated_err(struct.pack, endian + 'H', cls(70000))
Bob Ippolitoeb621272006-05-24 15:32:06 +0000456
Benjamin Petersond5299862008-06-11 01:31:28 +0000457 deprecated_err(struct.pack, endian + 'I', sys.maxint * 4L)
458 deprecated_err(struct.pack, endian + 'L', sys.maxint * 4L)
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000459 deprecated_err(struct.pack, endian + 'Q', 2**64)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000460
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000461 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000462 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
463 for endian in ('', '>', '<'):
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000464 for fmt in ('B', 'H', 'I', 'L', 'Q', 'b', 'h', 'i', 'l', 'q'):
Benjamin Petersond5299862008-06-11 01:31:28 +0000465 self.check_float_coerce(endian + fmt, 1.0)
466 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000467
Georg Brandl6269fec2009-01-01 12:15:31 +0000468 def test_issue4228(self):
469 # Packing a long may yield either 32 or 64 bits
470 x = struct.pack('L', -1)[:4]
471 self.assertEqual(x, '\xff'*4)
472
Benjamin Petersond5299862008-06-11 01:31:28 +0000473 def test_unpack_from(self):
474 test_string = 'abcd01234'
475 fmt = '4s'
476 s = struct.Struct(fmt)
477 for cls in (str, buffer):
478 data = cls(test_string)
479 self.assertEqual(s.unpack_from(data), ('abcd',))
480 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
481 self.assertEqual(s.unpack_from(data, 4), ('0123',))
482 for i in xrange(6):
483 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
484 for i in xrange(6, len(test_string) + 1):
485 self.assertRaises(struct.error, s.unpack_from, data, i)
486 for cls in (str, buffer):
487 data = cls(test_string)
488 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
489 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
490 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
491 for i in xrange(6):
492 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
493 for i in xrange(6, len(test_string) + 1):
494 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000495
Benjamin Petersond5299862008-06-11 01:31:28 +0000496 def test_pack_into(self):
497 test_string = 'Reykjavik rocks, eow!'
498 writable_buf = array.array('c', ' '*100)
499 fmt = '21s'
500 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000501
Benjamin Petersond5299862008-06-11 01:31:28 +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)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000506
Benjamin Petersond5299862008-06-11 01:31:28 +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)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000511
Benjamin Petersond5299862008-06-11 01:31:28 +0000512 # Go beyond boundaries.
513 small_buf = array.array('c', ' '*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)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000516
Georg Brandl0638a082009-02-13 11:03:59 +0000517 # Test bogus offset (issue 3694)
518 sb = small_buf
519 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
520
Benjamin Petersond5299862008-06-11 01:31:28 +0000521 def test_pack_into_fn(self):
522 test_string = 'Reykjavik rocks, eow!'
523 writable_buf = array.array('c', ' '*100)
524 fmt = '21s'
525 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000526
Benjamin Petersond5299862008-06-11 01:31:28 +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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000531
Benjamin Petersond5299862008-06-11 01:31:28 +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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000536
Benjamin Petersond5299862008-06-11 01:31:28 +0000537 # Go beyond boundaries.
538 small_buf = array.array('c', ' '*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)
Martin Blais2856e5f2006-05-26 12:03:27 +0000541
Benjamin Petersond5299862008-06-11 01:31:28 +0000542 def test_unpack_with_buffer(self):
543 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
544 data1 = array.array('B', '\x12\x34\x56\x78')
545 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
546 for data in [data1, data2]:
547 value, = struct.unpack('>I', data)
548 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000549
Benjamin Petersond5299862008-06-11 01:31:28 +0000550 def test_bool(self):
551 for prefix in tuple("<>!=")+('',):
552 false = (), [], [], '', 0
553 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000554
Benjamin Petersond5299862008-06-11 01:31:28 +0000555 falseFormat = prefix + '?' * len(false)
556 packedFalse = struct.pack(falseFormat, *false)
557 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000558
Benjamin Petersond5299862008-06-11 01:31:28 +0000559 trueFormat = prefix + '?' * len(true)
560 packedTrue = struct.pack(trueFormat, *true)
561 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000562
Benjamin Petersond5299862008-06-11 01:31:28 +0000563 self.assertEqual(len(true), len(unpackedTrue))
564 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000565
Benjamin Petersond5299862008-06-11 01:31:28 +0000566 for t in unpackedFalse:
567 self.assertFalse(t)
568 for t in unpackedTrue:
569 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000570
Benjamin Petersond5299862008-06-11 01:31:28 +0000571 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000572
Benjamin Petersond5299862008-06-11 01:31:28 +0000573 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000574
Benjamin Petersond5299862008-06-11 01:31:28 +0000575 if len(packed) != 1:
576 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
577 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000578
Benjamin Petersond5299862008-06-11 01:31:28 +0000579 for c in '\x01\x7f\xff\x0f\xf0':
580 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000581
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000582 if IS32BIT:
583 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000584 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000585
586
Tim Petersf733abb2007-01-30 03:03:46 +0000587
Benjamin Petersond5299862008-06-11 01:31:28 +0000588def test_main():
589 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000590
Benjamin Petersond5299862008-06-11 01:31:28 +0000591if __name__ == '__main__':
592 test_main()