blob: 4ddb79c881eaca61eb7122e936b5d137493a1fe4 [file] [log] [blame]
Florent Xiclunadb4a3212010-03-20 22:21:02 +00001import os
Martin Blais2856e5f2006-05-26 12:03:27 +00002import array
Benjamin Petersond5299862008-06-11 01:31:28 +00003import unittest
4import struct
Florent Xiclunadb4a3212010-03-20 22:21:02 +00005import inspect
Meador Inge68123462012-07-28 21:58:44 -05006from test.test_support import (run_unittest, check_warnings,
7 check_py3k_warnings, cpython_only)
Benjamin Petersond5299862008-06-11 01:31:28 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000011IS32BIT = sys.maxsize == 0x7fffffff
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000012
13integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
14
Florent Xiclunadb4a3212010-03-20 22:21:02 +000015testmod_filename = os.path.splitext(__file__)[0] + '.py'
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000016# Native 'q' packing isn't available on systems that don't have the C
17# long long type.
18try:
19 struct.pack('q', 5)
20except struct.error:
21 HAVE_LONG_LONG = False
22else:
23 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000024
25def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000026 return "".join(reversed(s))
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
Benjamin Petersond5299862008-06-11 01:31:28 +000034class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000035
Meador Inge68123462012-07-28 21:58:44 -050036 def setUp(self):
37 # due to missing size_t information from struct, it is assumed that
38 # sizeof(Py_ssize_t) = sizeof(void*)
39 self.header = 'PP'
40 if hasattr(sys, "gettotalrefcount"):
41 self.header += '2P'
42
43 def check_sizeof(self, format_str, number_of_codes):
44 def size(fmt):
45 """Wrapper around struct.calcsize which enforces the alignment
46 of the end of a structure to the alignment requirement of pointer.
47
48 Note: This wrapper should only be used if a pointer member is
49 included and no member with a size larger than a pointer exists.
50 """
51 return struct.calcsize(fmt + '0P')
52
53 struct_obj = struct.Struct(format_str)
54 # The size of 'PyStructObject'
55 totalsize = size(self.header + '5P')
56 # The size taken up by the 'formatcode' dynamic array
57 totalsize += size('3P') * (number_of_codes + 1)
58 result = sys.getsizeof(struct_obj)
59 msg = 'wrong size for %s: got %d, expected %d' \
60 % (type(struct_obj), result, totalsize)
61 self.assertEqual(result, totalsize, msg)
62
Benjamin Petersond5299862008-06-11 01:31:28 +000063 def check_float_coerce(self, format, number):
Mark Dickinson154b7ad2010-03-07 16:24:45 +000064 # SF bug 1530559. struct.pack raises TypeError where it used
65 # to convert.
Florent Xiclunadb4a3212010-03-20 22:21:02 +000066 with check_warnings((".*integer argument expected, got float",
67 DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +000068 got = struct.pack(format, number)
Florent Xiclunadb4a3212010-03-20 22:21:02 +000069 lineno = inspect.currentframe().f_lineno - 1
70 self.assertEqual(w.filename, testmod_filename)
71 self.assertEqual(w.lineno, lineno)
72 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +000073 expected = struct.pack(format, int(number))
74 self.assertEqual(got, expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +000075
Benjamin Petersond5299862008-06-11 01:31:28 +000076 def test_isbigendian(self):
77 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000078
Benjamin Petersond5299862008-06-11 01:31:28 +000079 def test_consistence(self):
80 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000081
Benjamin Petersond5299862008-06-11 01:31:28 +000082 sz = struct.calcsize('i')
83 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Benjamin Petersond5299862008-06-11 01:31:28 +000085 fmt = 'cbxxxxxxhhhhiillffd?'
86 fmt3 = '3c3b18x12h6i6l6f3d3?'
87 sz = struct.calcsize(fmt)
88 sz3 = struct.calcsize(fmt3)
89 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Benjamin Petersond5299862008-06-11 01:31:28 +000091 self.assertRaises(struct.error, struct.pack, 'iii', 3)
92 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Peterson0b00b6b2010-07-09 13:33:03 +000093 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
94 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Benjamin Petersond5299862008-06-11 01:31:28 +000095 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
96 s = struct.pack('ii', 1, 2)
97 self.assertRaises(struct.error, struct.unpack, 'iii', s)
98 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000099
Benjamin Petersond5299862008-06-11 01:31:28 +0000100 def test_transitiveness(self):
101 c = 'a'
102 b = 1
103 h = 255
104 i = 65535
105 l = 65536
106 f = 3.1415
107 d = 3.1415
108 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000109
Benjamin Petersond5299862008-06-11 01:31:28 +0000110 for prefix in ('', '@', '<', '>', '=', '!'):
111 for format in ('xcbhilfd?', 'xcBHILfd?'):
112 format = prefix + format
113 s = struct.pack(format, c, b, h, i, l, f, d, t)
114 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
115 self.assertEqual(cp, c)
116 self.assertEqual(bp, b)
117 self.assertEqual(hp, h)
118 self.assertEqual(ip, i)
119 self.assertEqual(lp, l)
120 self.assertEqual(int(100 * fp), int(100 * f))
121 self.assertEqual(int(100 * dp), int(100 * d))
122 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000123
Benjamin Petersond5299862008-06-11 01:31:28 +0000124 def test_new_features(self):
125 # Test some of the new features in detail
126 # (format, argument, big-endian result, little-endian result, asymmetric)
127 tests = [
128 ('c', 'a', 'a', 'a', 0),
129 ('xc', 'a', '\0a', '\0a', 0),
130 ('cx', 'a', 'a\0', 'a\0', 0),
131 ('s', 'a', 'a', 'a', 0),
132 ('0s', 'helloworld', '', '', 1),
133 ('1s', 'helloworld', 'h', 'h', 1),
134 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
135 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
136 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
137 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
138 ('b', 7, '\7', '\7', 0),
139 ('b', -7, '\371', '\371', 0),
140 ('B', 7, '\7', '\7', 0),
141 ('B', 249, '\371', '\371', 0),
142 ('h', 700, '\002\274', '\274\002', 0),
143 ('h', -700, '\375D', 'D\375', 0),
144 ('H', 700, '\002\274', '\274\002', 0),
145 ('H', 0x10000-700, '\375D', 'D\375', 0),
146 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
147 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
148 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
149 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
150 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
151 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
152 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
153 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
154 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
155 ('d', 2.0, '@\000\000\000\000\000\000\000',
156 '\000\000\000\000\000\000\000@', 0),
157 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
158 ('d', -2.0, '\300\000\000\000\000\000\000\000',
159 '\000\000\000\000\000\000\000\300', 0),
160 ('?', 0, '\0', '\0', 0),
161 ('?', 3, '\1', '\1', 1),
162 ('?', True, '\1', '\1', 0),
163 ('?', [], '\0', '\0', 1),
164 ('?', (1,), '\1', '\1', 1),
165 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000166
Benjamin Petersond5299862008-06-11 01:31:28 +0000167 for fmt, arg, big, lil, asy in tests:
168 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
169 ('='+fmt, ISBIGENDIAN and big or lil)]:
170 res = struct.pack(xfmt, arg)
171 self.assertEqual(res, exp)
172 self.assertEqual(struct.calcsize(xfmt), len(res))
173 rev = struct.unpack(xfmt, res)[0]
174 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000175 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000176
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000177 def test_calcsize(self):
178 expected_size = {
179 'b': 1, 'B': 1,
180 'h': 2, 'H': 2,
181 'i': 4, 'I': 4,
182 'l': 4, 'L': 4,
183 'q': 8, 'Q': 8,
184 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000185
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000186 # standard integer sizes
187 for code in integer_codes:
188 for byteorder in ('=', '<', '>', '!'):
189 format = byteorder+code
190 size = struct.calcsize(format)
191 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000192
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000193 # native integer sizes, except 'q' and 'Q'
194 for format_pair in ('bB', 'hH', 'iI', 'lL'):
195 for byteorder in ['', '@']:
196 signed_size = struct.calcsize(byteorder + format_pair[0])
197 unsigned_size = struct.calcsize(byteorder + format_pair[1])
198 self.assertEqual(signed_size, unsigned_size)
199
200 # bounds for native integer sizes
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000201 self.assertEqual(struct.calcsize('b'), 1)
202 self.assertLessEqual(2, struct.calcsize('h'))
203 self.assertLessEqual(4, struct.calcsize('l'))
204 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
205 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000206
207 # tests for native 'q' and 'Q' when applicable
208 if HAVE_LONG_LONG:
209 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000210 self.assertLessEqual(8, struct.calcsize('q'))
211 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000212
213 def test_integers(self):
214 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000215 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000216
Benjamin Petersond5299862008-06-11 01:31:28 +0000217 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000218 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000219 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000220 self.format = format
221 self.code = format[-1]
222 self.direction = format[:-1]
223 if not self.direction in ('', '@', '=', '<', '>', '!'):
224 raise ValueError("unrecognized packing direction: %s" %
225 self.direction)
226 self.bytesize = struct.calcsize(format)
227 self.bitsize = self.bytesize * 8
228 if self.code in tuple('bhilq'):
229 self.signed = True
230 self.min_value = -(2L**(self.bitsize-1))
231 self.max_value = 2L**(self.bitsize-1) - 1
232 elif self.code in tuple('BHILQ'):
233 self.signed = False
234 self.min_value = 0
235 self.max_value = 2L**self.bitsize - 1
236 else:
237 raise ValueError("unrecognized format code: %s" %
238 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000239
Benjamin Petersond5299862008-06-11 01:31:28 +0000240 def test_one(self, x, pack=struct.pack,
241 unpack=struct.unpack,
242 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000243
244 format = self.format
245 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000246 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000247 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000248 expected += 1L << self.bitsize
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000249 self.assertGreaterEqual(expected, 0)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000250 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000251 if len(expected) & 1:
252 expected = "0" + expected
253 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000254 expected = ("\x00" * (self.bytesize - len(expected)) +
255 expected)
256 if (self.direction == '<' or
257 self.direction in ('', '@', '=') and not ISBIGENDIAN):
258 expected = string_reverse(expected)
259 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000260
Benjamin Petersond5299862008-06-11 01:31:28 +0000261 # Pack work?
262 got = pack(format, x)
263 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000264
Benjamin Petersond5299862008-06-11 01:31:28 +0000265 # Unpack work?
266 retrieved = unpack(format, got)[0]
267 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000268
Benjamin Petersond5299862008-06-11 01:31:28 +0000269 # Adding any byte should cause a "too big" error.
270 self.assertRaises((struct.error, TypeError), unpack, format,
271 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000272 else:
273 # x is out of range -- verify pack realizes that.
Benjamin Peterson9d8c4562010-07-10 15:17:08 +0000274 self.assertRaises((OverflowError, ValueError, struct.error),
275 pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000276
277 def run(self):
278 from random import randrange
279
280 # Create all interesting powers of 2.
281 values = []
282 for exp in range(self.bitsize + 3):
283 values.append(1L << exp)
284
285 # Add some random values.
286 for i in range(self.bitsize):
287 val = 0L
288 for j in range(self.bytesize):
289 val = (val << 8) | randrange(256)
290 values.append(val)
291
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000292 # Values absorbed from other tests
293 values.extend([300, 700000, sys.maxint*4])
294
295 # Try all those, and their negations, and +-1 from
296 # them. Note that this tests all power-of-2
297 # boundaries in range, and a few out of range, plus
298 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000299 for base in values:
300 for val in -base, base:
301 for incr in -1, 0, 1:
302 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000303 self.test_one(int(x))
304 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000305
306 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000307 class NotAnIntNS(object):
308 def __int__(self):
309 return 42
310
311 def __long__(self):
312 return 1729L
313
314 class NotAnIntOS:
315 def __int__(self):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000316 return 85
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000317
318 def __long__(self):
319 return -163L
320
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000321 # Objects with an '__index__' method should be allowed
322 # to pack as integers. That is assuming the implemented
323 # '__index__' method returns and 'int' or 'long'.
324 class Indexable(object):
325 def __init__(self, value):
326 self._value = value
327
328 def __index__(self):
329 return self._value
330
331 # If the '__index__' method raises a type error, then
332 # '__int__' should be used with a deprecation warning.
333 class BadIndex(object):
334 def __index__(self):
335 raise TypeError
336
337 def __int__(self):
338 return 42
339
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000340 self.assertRaises((TypeError, struct.error),
341 struct.pack, self.format,
342 "a string")
343 self.assertRaises((TypeError, struct.error),
344 struct.pack, self.format,
345 randrange)
346 with check_warnings(("integer argument expected, "
347 "got non-integer", DeprecationWarning)):
Benjamin Peterson8e93f4e2010-07-09 18:15:28 +0000348 with self.assertRaises((TypeError, struct.error)):
349 struct.pack(self.format, 3+42j)
Benjamin Petersond5299862008-06-11 01:31:28 +0000350
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000351 # an attempt to convert a non-integer (with an
352 # implicit conversion via __int__) should succeed,
353 # with a DeprecationWarning
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000354 for nonint in NotAnIntNS(), NotAnIntOS(), BadIndex():
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000355 with check_warnings((".*integer argument expected, got non"
356 "-integer", DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000357 got = struct.pack(self.format, nonint)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000358 lineno = inspect.currentframe().f_lineno - 1
359 self.assertEqual(w.filename, testmod_filename)
360 self.assertEqual(w.lineno, lineno)
361 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000362 expected = struct.pack(self.format, int(nonint))
363 self.assertEqual(got, expected)
364
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000365 # Check for legitimate values from '__index__'.
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000366 for obj in (Indexable(0), Indexable(10), Indexable(17),
367 Indexable(42), Indexable(100), Indexable(127)):
368 try:
369 struct.pack(format, obj)
370 except:
371 self.fail("integer code pack failed on object "
372 "with '__index__' method")
373
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000374 # Check for bogus values from '__index__'.
375 for obj in (Indexable('a'), Indexable(u'b'), Indexable(None),
376 Indexable({'a': 1}), Indexable([1, 2, 3])):
377 self.assertRaises((TypeError, struct.error),
378 struct.pack, self.format,
379 obj)
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000380
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000381 byteorders = '', '@', '=', '<', '>', '!'
382 for code in integer_codes:
383 for byteorder in byteorders:
384 if (byteorder in ('', '@') and code in ('q', 'Q') and
385 not HAVE_LONG_LONG):
386 continue
387 format = byteorder+code
388 t = IntTester(format)
389 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000390
391 def test_p_code(self):
392 # Test p ("Pascal string") code.
393 for code, input, expected, expectedback in [
394 ('p','abc', '\x00', ''),
395 ('1p', 'abc', '\x00', ''),
396 ('2p', 'abc', '\x01a', 'a'),
397 ('3p', 'abc', '\x02ab', 'ab'),
398 ('4p', 'abc', '\x03abc', 'abc'),
399 ('5p', 'abc', '\x03abc\x00', 'abc'),
400 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
401 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
402 got = struct.pack(code, input)
403 self.assertEqual(got, expected)
404 (got,) = struct.unpack(code, got)
405 self.assertEqual(got, expectedback)
406
407 def test_705836(self):
408 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
409 # from the low-order discarded bits could propagate into the exponent
410 # field, causing the result to be wrong by a factor of 2.
411 import math
412
413 for base in range(1, 33):
414 # smaller <- largest representable float less than base.
415 delta = 0.5
416 while base - delta / 2.0 != base:
417 delta /= 2.0
418 smaller = base - delta
419 # Packing this rounds away a solid string of trailing 1 bits.
420 packed = struct.pack("<f", smaller)
421 unpacked = struct.unpack("<f", packed)[0]
422 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
423 # 16, respectively.
424 self.assertEqual(base, unpacked)
425 bigpacked = struct.pack(">f", smaller)
426 self.assertEqual(bigpacked, string_reverse(packed))
427 unpacked = struct.unpack(">f", bigpacked)[0]
428 self.assertEqual(base, unpacked)
429
430 # Largest finite IEEE single.
431 big = (1 << 24) - 1
432 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000433 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000434 unpacked = struct.unpack(">f", packed)[0]
435 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000436
Benjamin Petersond5299862008-06-11 01:31:28 +0000437 # The same, but tack on a 1 bit so it rounds up to infinity.
438 big = (1 << 25) - 1
439 big = math.ldexp(big, 127 - 24)
440 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000441
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000442 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000443 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
444 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000445 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000446 self.check_float_coerce(endian + fmt, 1.0)
447 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000448
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000449 def test_unpack_from(self, cls=str):
450 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000451 fmt = '4s'
452 s = struct.Struct(fmt)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000453
454 self.assertEqual(s.unpack_from(data), ('abcd',))
455 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
456 for i in xrange(6):
457 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
458 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
459 for i in xrange(6, len(data) + 1):
460 self.assertRaises(struct.error, s.unpack_from, data, i)
461 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000462
Benjamin Petersond5299862008-06-11 01:31:28 +0000463 def test_pack_into(self):
464 test_string = 'Reykjavik rocks, eow!'
465 writable_buf = array.array('c', ' '*100)
466 fmt = '21s'
467 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000468
Benjamin Petersond5299862008-06-11 01:31:28 +0000469 # Test without offset
470 s.pack_into(writable_buf, 0, test_string)
471 from_buf = writable_buf.tostring()[:len(test_string)]
472 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000473
Benjamin Petersond5299862008-06-11 01:31:28 +0000474 # Test with offset.
475 s.pack_into(writable_buf, 10, test_string)
476 from_buf = writable_buf.tostring()[:len(test_string)+10]
477 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000478
Benjamin Petersond5299862008-06-11 01:31:28 +0000479 # Go beyond boundaries.
480 small_buf = array.array('c', ' '*10)
Benjamin Peterson86ac22e2010-07-07 23:26:57 +0000481 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
482 test_string)
483 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
484 test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000485
Georg Brandl0638a082009-02-13 11:03:59 +0000486 # Test bogus offset (issue 3694)
487 sb = small_buf
Benjamin Peterson0b00b6b2010-07-09 13:33:03 +0000488 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
489 None)
Georg Brandl0638a082009-02-13 11:03:59 +0000490
Benjamin Petersond5299862008-06-11 01:31:28 +0000491 def test_pack_into_fn(self):
492 test_string = 'Reykjavik rocks, eow!'
493 writable_buf = array.array('c', ' '*100)
494 fmt = '21s'
495 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000496
Benjamin Petersond5299862008-06-11 01:31:28 +0000497 # Test without offset.
498 pack_into(writable_buf, 0, test_string)
499 from_buf = writable_buf.tostring()[:len(test_string)]
500 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000501
Benjamin Petersond5299862008-06-11 01:31:28 +0000502 # Test with offset.
503 pack_into(writable_buf, 10, test_string)
504 from_buf = writable_buf.tostring()[:len(test_string)+10]
505 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000506
Benjamin Petersond5299862008-06-11 01:31:28 +0000507 # Go beyond boundaries.
508 small_buf = array.array('c', ' '*10)
Benjamin Peterson86ac22e2010-07-07 23:26:57 +0000509 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
510 test_string)
511 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
512 test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000513
Benjamin Petersond5299862008-06-11 01:31:28 +0000514 def test_unpack_with_buffer(self):
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000515 with check_py3k_warnings(("buffer.. not supported in 3.x",
516 DeprecationWarning)):
517 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
518 data1 = array.array('B', '\x12\x34\x56\x78')
519 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
520 for data in [data1, data2]:
521 value, = struct.unpack('>I', data)
522 self.assertEqual(value, 0x12345678)
523
524 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000525
Benjamin Petersond5299862008-06-11 01:31:28 +0000526 def test_bool(self):
Benjamin Peterson489113f2010-07-07 19:03:36 +0000527 class ExplodingBool(object):
528 def __nonzero__(self):
529 raise IOError
Benjamin Petersond5299862008-06-11 01:31:28 +0000530 for prefix in tuple("<>!=")+('',):
531 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000532 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000533
Benjamin Petersond5299862008-06-11 01:31:28 +0000534 falseFormat = prefix + '?' * len(false)
535 packedFalse = struct.pack(falseFormat, *false)
536 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000537
Benjamin Petersond5299862008-06-11 01:31:28 +0000538 trueFormat = prefix + '?' * len(true)
539 packedTrue = struct.pack(trueFormat, *true)
540 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000541
Benjamin Petersond5299862008-06-11 01:31:28 +0000542 self.assertEqual(len(true), len(unpackedTrue))
543 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000544
Benjamin Petersond5299862008-06-11 01:31:28 +0000545 for t in unpackedFalse:
546 self.assertFalse(t)
547 for t in unpackedTrue:
548 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000549
Benjamin Petersond5299862008-06-11 01:31:28 +0000550 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000551
Benjamin Petersond5299862008-06-11 01:31:28 +0000552 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000553
Benjamin Petersond5299862008-06-11 01:31:28 +0000554 if len(packed) != 1:
555 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
556 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000557
Benjamin Peterson489113f2010-07-07 19:03:36 +0000558 self.assertRaises(IOError, struct.pack, prefix + '?',
559 ExplodingBool())
560
561 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
562 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000563
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000564 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
565 def test_crasher(self):
566 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000567
Mark Dickinson40228912010-06-11 20:27:05 +0000568 def test_count_overflow(self):
569 hugecount = '{}b'.format(sys.maxsize+1)
570 self.assertRaises(struct.error, struct.calcsize, hugecount)
571
572 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
573 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000574
Meador Inge68123462012-07-28 21:58:44 -0500575 @cpython_only
576 def test__sizeof__(self):
577 for code in integer_codes:
578 self.check_sizeof(code, 1)
579 self.check_sizeof('BHILfdspP', 9)
580 self.check_sizeof('B' * 1234, 1234)
581 self.check_sizeof('fd', 2)
582 self.check_sizeof('xxxxxxxxxxxxxx', 0)
583 self.check_sizeof('100H', 100)
584 self.check_sizeof('187s', 1)
585 self.check_sizeof('20p', 1)
586 self.check_sizeof('0s', 1)
587 self.check_sizeof('0c', 0)
Meador Inge87c5b942012-07-23 09:27:00 -0500588
Benjamin Petersond5299862008-06-11 01:31:28 +0000589def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000590 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000591
Benjamin Petersond5299862008-06-11 01:31:28 +0000592if __name__ == '__main__':
593 test_main()