blob: 9f1fceeb71bf307c16861682a4611e8e8bcad6f6 [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
Mark Dickinsonca6b5f32009-07-07 11:08:23 +0000468 @unittest.skipUnless(PY_STRUCT_OVERFLOW_MASKING,
469 "only applies when overflow masking enabled")
Georg Brandl6269fec2009-01-01 12:15:31 +0000470 def test_issue4228(self):
471 # Packing a long may yield either 32 or 64 bits
472 x = struct.pack('L', -1)[:4]
473 self.assertEqual(x, '\xff'*4)
474
Benjamin Petersond5299862008-06-11 01:31:28 +0000475 def test_unpack_from(self):
476 test_string = 'abcd01234'
477 fmt = '4s'
478 s = struct.Struct(fmt)
479 for cls in (str, buffer):
480 data = cls(test_string)
481 self.assertEqual(s.unpack_from(data), ('abcd',))
482 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
483 self.assertEqual(s.unpack_from(data, 4), ('0123',))
484 for i in xrange(6):
485 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
486 for i in xrange(6, len(test_string) + 1):
487 self.assertRaises(struct.error, s.unpack_from, data, i)
488 for cls in (str, buffer):
489 data = cls(test_string)
490 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
491 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
492 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
493 for i in xrange(6):
494 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
495 for i in xrange(6, len(test_string) + 1):
496 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000497
Benjamin Petersond5299862008-06-11 01:31:28 +0000498 def test_pack_into(self):
499 test_string = 'Reykjavik rocks, eow!'
500 writable_buf = array.array('c', ' '*100)
501 fmt = '21s'
502 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000503
Benjamin Petersond5299862008-06-11 01:31:28 +0000504 # Test without offset
505 s.pack_into(writable_buf, 0, test_string)
506 from_buf = writable_buf.tostring()[:len(test_string)]
507 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000508
Benjamin Petersond5299862008-06-11 01:31:28 +0000509 # Test with offset.
510 s.pack_into(writable_buf, 10, test_string)
511 from_buf = writable_buf.tostring()[:len(test_string)+10]
512 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000513
Benjamin Petersond5299862008-06-11 01:31:28 +0000514 # Go beyond boundaries.
515 small_buf = array.array('c', ' '*10)
516 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
517 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000518
Georg Brandl0638a082009-02-13 11:03:59 +0000519 # Test bogus offset (issue 3694)
520 sb = small_buf
521 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
522
Benjamin Petersond5299862008-06-11 01:31:28 +0000523 def test_pack_into_fn(self):
524 test_string = 'Reykjavik rocks, eow!'
525 writable_buf = array.array('c', ' '*100)
526 fmt = '21s'
527 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000528
Benjamin Petersond5299862008-06-11 01:31:28 +0000529 # Test without offset.
530 pack_into(writable_buf, 0, test_string)
531 from_buf = writable_buf.tostring()[:len(test_string)]
532 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000533
Benjamin Petersond5299862008-06-11 01:31:28 +0000534 # Test with offset.
535 pack_into(writable_buf, 10, test_string)
536 from_buf = writable_buf.tostring()[:len(test_string)+10]
537 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000538
Benjamin Petersond5299862008-06-11 01:31:28 +0000539 # Go beyond boundaries.
540 small_buf = array.array('c', ' '*10)
541 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
542 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000543
Benjamin Petersond5299862008-06-11 01:31:28 +0000544 def test_unpack_with_buffer(self):
545 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
546 data1 = array.array('B', '\x12\x34\x56\x78')
547 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
548 for data in [data1, data2]:
549 value, = struct.unpack('>I', data)
550 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000551
Benjamin Petersond5299862008-06-11 01:31:28 +0000552 def test_bool(self):
553 for prefix in tuple("<>!=")+('',):
554 false = (), [], [], '', 0
555 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000556
Benjamin Petersond5299862008-06-11 01:31:28 +0000557 falseFormat = prefix + '?' * len(false)
558 packedFalse = struct.pack(falseFormat, *false)
559 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000560
Benjamin Petersond5299862008-06-11 01:31:28 +0000561 trueFormat = prefix + '?' * len(true)
562 packedTrue = struct.pack(trueFormat, *true)
563 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000564
Benjamin Petersond5299862008-06-11 01:31:28 +0000565 self.assertEqual(len(true), len(unpackedTrue))
566 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000567
Benjamin Petersond5299862008-06-11 01:31:28 +0000568 for t in unpackedFalse:
569 self.assertFalse(t)
570 for t in unpackedTrue:
571 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000572
Benjamin Petersond5299862008-06-11 01:31:28 +0000573 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000574
Benjamin Petersond5299862008-06-11 01:31:28 +0000575 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000576
Benjamin Petersond5299862008-06-11 01:31:28 +0000577 if len(packed) != 1:
578 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
579 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000580
Benjamin Petersond5299862008-06-11 01:31:28 +0000581 for c in '\x01\x7f\xff\x0f\xf0':
582 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000583
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000584 if IS32BIT:
585 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000586 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000587
588
Tim Petersf733abb2007-01-30 03:03:46 +0000589
Benjamin Petersond5299862008-06-11 01:31:28 +0000590def test_main():
591 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000592
Benjamin Petersond5299862008-06-11 01:31:28 +0000593if __name__ == '__main__':
594 test_main()