blob: 919cd6373d15cf455060f0ce7ab3141eb56e7a70 [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
Tim Peters17e17d42001-06-13 22:45:27 +00004import sys
Mark Dickinson79d38ac2010-03-05 14:44:08 +00005
Meador Inge90bc2dbc2012-07-28 22:16:39 -05006from test.support import run_unittest, cpython_only
Mark Dickinson79d38ac2010-03-05 14:44:08 +00007
Tim Peters17e17d42001-06-13 22:45:27 +00008ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00009IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000010
Antoine Pitrou45d9c912011-10-06 15:27:40 +020011integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000012byteorders = '', '@', '=', '<', '>', '!'
13
Antoine Pitrou45d9c912011-10-06 15:27:40 +020014def iter_integer_formats(byteorders=byteorders):
15 for code in integer_codes:
16 for byteorder in byteorders:
17 if (byteorder in ('', '@') and code in ('q', 'Q') and
18 not HAVE_LONG_LONG):
19 continue
20 if (byteorder not in ('', '@') and code in ('n', 'N')):
21 continue
22 yield code, byteorder
23
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000024# Native 'q' packing isn't available on systems that don't have the C
25# long long type.
26try:
27 struct.pack('q', 5)
28except struct.error:
29 HAVE_LONG_LONG = False
30else:
31 HAVE_LONG_LONG = True
32
Tim Peters17e17d42001-06-13 22:45:27 +000033def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000034 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000035
36def bigendian_to_native(value):
37 if ISBIGENDIAN:
38 return value
39 else:
40 return string_reverse(value)
41
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000042class StructTest(unittest.TestCase):
Meador Inge90bc2dbc2012-07-28 22:16:39 -050043 def setUp(self):
44 # due to missing size_t information from struct, it is assumed that
45 # sizeof(Py_ssize_t) = sizeof(void*)
46 self.header = 'PP'
47 if hasattr(sys, "gettotalrefcount"):
48 self.header += '2P'
49
50 def check_sizeof(self, format_str, number_of_codes):
51 def size(fmt):
52 """Wrapper around struct.calcsize which enforces the alignment
53 of the end of a structure to the alignment requirement of pointer.
54
55 Note: This wrapper should only be used if a pointer member is
56 included and no member with a size larger than a pointer exists.
57 """
58 return struct.calcsize(fmt + '0P')
59
60 struct_obj = struct.Struct(format_str)
61 # The size of 'PyStructObject'
62 totalsize = size(self.header + '5P')
63 # The size taken up by the 'formatcode' dynamic array
64 totalsize += size('3P') * (number_of_codes + 1)
65 result = sys.getsizeof(struct_obj)
66 msg = 'wrong size for %s: got %d, expected %d' \
67 % (type(struct_obj), result, totalsize)
68 self.assertEqual(result, totalsize, msg)
69
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000070 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000071 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000072
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000073 def test_consistence(self):
74 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000075
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000076 sz = struct.calcsize('i')
77 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000078
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000079 fmt = 'cbxxxxxxhhhhiillffd?'
80 fmt3 = '3c3b18x12h6i6l6f3d3?'
81 sz = struct.calcsize(fmt)
82 sz3 = struct.calcsize(fmt3)
83 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000084
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000085 self.assertRaises(struct.error, struct.pack, 'iii', 3)
86 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000087 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
88 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000089 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
90 s = struct.pack('ii', 1, 2)
91 self.assertRaises(struct.error, struct.unpack, 'iii', s)
92 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000094 def test_transitiveness(self):
95 c = b'a'
96 b = 1
97 h = 255
98 i = 65535
99 l = 65536
100 f = 3.1415
101 d = 3.1415
102 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +0000103
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000104 for prefix in ('', '@', '<', '>', '=', '!'):
105 for format in ('xcbhilfd?', 'xcBHILfd?'):
106 format = prefix + format
107 s = struct.pack(format, c, b, h, i, l, f, d, t)
108 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
109 self.assertEqual(cp, c)
110 self.assertEqual(bp, b)
111 self.assertEqual(hp, h)
112 self.assertEqual(ip, i)
113 self.assertEqual(lp, l)
114 self.assertEqual(int(100 * fp), int(100 * f))
115 self.assertEqual(int(100 * dp), int(100 * d))
116 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000117
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000118 def test_new_features(self):
119 # Test some of the new features in detail
120 # (format, argument, big-endian result, little-endian result, asymmetric)
121 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000122 ('c', b'a', b'a', b'a', 0),
123 ('xc', b'a', b'\0a', b'\0a', 0),
124 ('cx', b'a', b'a\0', b'a\0', 0),
125 ('s', b'a', b'a', b'a', 0),
126 ('0s', b'helloworld', b'', b'', 1),
127 ('1s', b'helloworld', b'h', b'h', 1),
128 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
129 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
130 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
131 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
132 ('b', 7, b'\7', b'\7', 0),
133 ('b', -7, b'\371', b'\371', 0),
134 ('B', 7, b'\7', b'\7', 0),
135 ('B', 249, b'\371', b'\371', 0),
136 ('h', 700, b'\002\274', b'\274\002', 0),
137 ('h', -700, b'\375D', b'D\375', 0),
138 ('H', 700, b'\002\274', b'\274\002', 0),
139 ('H', 0x10000-700, b'\375D', b'D\375', 0),
140 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
141 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
142 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
143 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
144 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
145 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
146 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
147 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
148 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
149 ('d', 2.0, b'@\000\000\000\000\000\000\000',
150 b'\000\000\000\000\000\000\000@', 0),
151 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
152 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
153 b'\000\000\000\000\000\000\000\300', 0),
154 ('?', 0, b'\0', b'\0', 0),
155 ('?', 3, b'\1', b'\1', 1),
156 ('?', True, b'\1', b'\1', 0),
157 ('?', [], b'\0', b'\0', 1),
158 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000159 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000160
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000161 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000162 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
163 ('='+fmt, ISBIGENDIAN and big or lil)]:
164 res = struct.pack(xfmt, arg)
165 self.assertEqual(res, exp)
166 self.assertEqual(struct.calcsize(xfmt), len(res))
167 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000168 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000169 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000170
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000171 def test_calcsize(self):
172 expected_size = {
173 'b': 1, 'B': 1,
174 'h': 2, 'H': 2,
175 'i': 4, 'I': 4,
176 'l': 4, 'L': 4,
177 'q': 8, 'Q': 8,
178 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000179
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000180 # standard integer sizes
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200181 for code, byteorder in iter_integer_formats(('=', '<', '>', '!')):
182 format = byteorder+code
183 size = struct.calcsize(format)
184 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000185
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000186 # native integer sizes
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200187 native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000188 if HAVE_LONG_LONG:
189 native_pairs += 'qQ',
190 for format_pair in native_pairs:
191 for byteorder in '', '@':
192 signed_size = struct.calcsize(byteorder + format_pair[0])
193 unsigned_size = struct.calcsize(byteorder + format_pair[1])
194 self.assertEqual(signed_size, unsigned_size)
195
196 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000197 self.assertEqual(struct.calcsize('b'), 1)
198 self.assertLessEqual(2, struct.calcsize('h'))
199 self.assertLessEqual(4, struct.calcsize('l'))
200 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
201 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000202 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000203 self.assertLessEqual(8, struct.calcsize('q'))
204 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200205 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i'))
206 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000207
208 def test_integers(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200209 # Integer tests (bBhHiIlLqQnN).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000210 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000211
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000212 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000213 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000214 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000215 self.format = format
216 self.code = format[-1]
217 self.byteorder = format[:-1]
218 if not self.byteorder in byteorders:
219 raise ValueError("unrecognized packing byteorder: %s" %
220 self.byteorder)
221 self.bytesize = struct.calcsize(format)
222 self.bitsize = self.bytesize * 8
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200223 if self.code in tuple('bhilqn'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000224 self.signed = True
225 self.min_value = -(2**(self.bitsize-1))
226 self.max_value = 2**(self.bitsize-1) - 1
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200227 elif self.code in tuple('BHILQN'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000228 self.signed = False
229 self.min_value = 0
230 self.max_value = 2**self.bitsize - 1
231 else:
232 raise ValueError("unrecognized format code: %s" %
233 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000234
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000235 def test_one(self, x, pack=struct.pack,
236 unpack=struct.unpack,
237 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000238
239 format = self.format
240 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000241 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000242 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000243 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000244 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000245 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000246 if len(expected) & 1:
247 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000248 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000249 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000250 expected = (b"\x00" * (self.bytesize - len(expected)) +
251 expected)
252 if (self.byteorder == '<' or
253 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
254 expected = string_reverse(expected)
255 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000256
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000257 # Pack work?
258 got = pack(format, x)
259 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000260
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000261 # Unpack work?
262 retrieved = unpack(format, got)[0]
263 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000264
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000265 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000266 self.assertRaises((struct.error, TypeError), unpack, format,
267 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268 else:
269 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000270 self.assertRaises((OverflowError, ValueError, struct.error),
271 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000272
273 def run(self):
274 from random import randrange
275
276 # Create all interesting powers of 2.
277 values = []
278 for exp in range(self.bitsize + 3):
279 values.append(1 << exp)
280
281 # Add some random values.
282 for i in range(self.bitsize):
283 val = 0
284 for j in range(self.bytesize):
285 val = (val << 8) | randrange(256)
286 values.append(val)
287
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000288 # Values absorbed from other tests
289 values.extend([300, 700000, sys.maxsize*4])
290
291 # Try all those, and their negations, and +-1 from
292 # them. Note that this tests all power-of-2
293 # boundaries in range, and a few out of range, plus
294 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000295 for base in values:
296 for val in -base, base:
297 for incr in -1, 0, 1:
298 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000299 self.test_one(x)
300
301 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000302 class NotAnInt:
303 def __int__(self):
304 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000305
Mark Dickinsone9493a12010-04-04 08:52:51 +0000306 # Objects with an '__index__' method should be allowed
307 # to pack as integers. That is assuming the implemented
308 # '__index__' method returns and 'int' or 'long'.
309 class Indexable(object):
310 def __init__(self, value):
311 self._value = value
312
313 def __index__(self):
314 return self._value
315
316 # If the '__index__' method raises a type error, then
317 # '__int__' should be used with a deprecation warning.
318 class BadIndex(object):
319 def __index__(self):
320 raise TypeError
321
322 def __int__(self):
323 return 42
324
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000325 self.assertRaises((TypeError, struct.error),
326 struct.pack, self.format,
327 "a string")
328 self.assertRaises((TypeError, struct.error),
329 struct.pack, self.format,
330 randrange)
331 self.assertRaises((TypeError, struct.error),
332 struct.pack, self.format,
333 3+42j)
334 self.assertRaises((TypeError, struct.error),
335 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000336 NotAnInt())
337 self.assertRaises((TypeError, struct.error),
338 struct.pack, self.format,
339 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000340
Mark Dickinsone9493a12010-04-04 08:52:51 +0000341 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000342 for obj in (Indexable(0), Indexable(10), Indexable(17),
343 Indexable(42), Indexable(100), Indexable(127)):
344 try:
345 struct.pack(format, obj)
346 except:
347 self.fail("integer code pack failed on object "
348 "with '__index__' method")
349
Mark Dickinsone9493a12010-04-04 08:52:51 +0000350 # Check for bogus values from '__index__'.
351 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
352 Indexable({'a': 1}), Indexable([1, 2, 3])):
353 self.assertRaises((TypeError, struct.error),
354 struct.pack, self.format,
355 obj)
356
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200357 for code, byteorder in iter_integer_formats():
358 format = byteorder+code
359 t = IntTester(format)
360 t.run()
361
362 def test_nN_code(self):
363 # n and N don't exist in standard sizes
364 def assertStructError(func, *args, **kwargs):
365 with self.assertRaises(struct.error) as cm:
366 func(*args, **kwargs)
367 self.assertIn("bad char in struct format", str(cm.exception))
368 for code in 'nN':
369 for byteorder in ('=', '<', '>', '!'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000370 format = byteorder+code
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200371 assertStructError(struct.calcsize, format)
372 assertStructError(struct.pack, format, 0)
373 assertStructError(struct.unpack, format, b"")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000374
375 def test_p_code(self):
376 # Test p ("Pascal string") code.
377 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000378 ('p', b'abc', b'\x00', b''),
379 ('1p', b'abc', b'\x00', b''),
380 ('2p', b'abc', b'\x01a', b'a'),
381 ('3p', b'abc', b'\x02ab', b'ab'),
382 ('4p', b'abc', b'\x03abc', b'abc'),
383 ('5p', b'abc', b'\x03abc\x00', b'abc'),
384 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
385 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000386 got = struct.pack(code, input)
387 self.assertEqual(got, expected)
388 (got,) = struct.unpack(code, got)
389 self.assertEqual(got, expectedback)
390
391 def test_705836(self):
392 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
393 # from the low-order discarded bits could propagate into the exponent
394 # field, causing the result to be wrong by a factor of 2.
395 import math
396
397 for base in range(1, 33):
398 # smaller <- largest representable float less than base.
399 delta = 0.5
400 while base - delta / 2.0 != base:
401 delta /= 2.0
402 smaller = base - delta
403 # Packing this rounds away a solid string of trailing 1 bits.
404 packed = struct.pack("<f", smaller)
405 unpacked = struct.unpack("<f", packed)[0]
406 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
407 # 16, respectively.
408 self.assertEqual(base, unpacked)
409 bigpacked = struct.pack(">f", smaller)
410 self.assertEqual(bigpacked, string_reverse(packed))
411 unpacked = struct.unpack(">f", bigpacked)[0]
412 self.assertEqual(base, unpacked)
413
414 # Largest finite IEEE single.
415 big = (1 << 24) - 1
416 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000417 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000418 unpacked = struct.unpack(">f", packed)[0]
419 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000420
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000421 # The same, but tack on a 1 bit so it rounds up to infinity.
422 big = (1 << 25) - 1
423 big = math.ldexp(big, 127 - 24)
424 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000425
Mark Dickinsonea835e72009-04-19 20:40:33 +0000426 def test_1530559(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200427 for code, byteorder in iter_integer_formats():
428 format = byteorder + code
429 self.assertRaises(struct.error, struct.pack, format, 1.0)
430 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000431 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
432 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
433
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000434 def test_unpack_from(self):
435 test_string = b'abcd01234'
436 fmt = '4s'
437 s = struct.Struct(fmt)
438 for cls in (bytes, bytearray):
439 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000440 self.assertEqual(s.unpack_from(data), (b'abcd',))
441 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
442 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
443 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000444 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000445 for i in range(6, len(test_string) + 1):
446 self.assertRaises(struct.error, s.unpack_from, data, i)
447 for cls in (bytes, bytearray):
448 data = cls(test_string)
449 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
450 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
451 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
452 for i in range(6):
453 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
454 for i in range(6, len(test_string) + 1):
455 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000456
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000457 def test_pack_into(self):
458 test_string = b'Reykjavik rocks, eow!'
459 writable_buf = array.array('b', b' '*100)
460 fmt = '21s'
461 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000462
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000463 # Test without offset
464 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000465 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000467
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000468 # Test with offset.
469 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000470 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000471 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000472
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000473 # Go beyond boundaries.
474 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000475 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
476 test_string)
477 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
478 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000479
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000480 # Test bogus offset (issue 3694)
481 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000482 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
483 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000484
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 def test_pack_into_fn(self):
486 test_string = b'Reykjavik rocks, eow!'
487 writable_buf = array.array('b', b' '*100)
488 fmt = '21s'
489 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000490
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000491 # Test without offset.
492 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000493 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000494 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000495
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000496 # Test with offset.
497 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000498 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000501 # Go beyond boundaries.
502 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000503 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
504 test_string)
505 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
506 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000507
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000508 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200509 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000510 data1 = array.array('B', b'\x12\x34\x56\x78')
511 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
512 for data in [data1, data2]:
513 value, = struct.unpack('>I', data)
514 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000515
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000516 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000517 class ExplodingBool(object):
518 def __bool__(self):
519 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000520 for prefix in tuple("<>!=")+('',):
521 false = (), [], [], '', 0
522 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000523
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000524 falseFormat = prefix + '?' * len(false)
525 packedFalse = struct.pack(falseFormat, *false)
526 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000528 trueFormat = prefix + '?' * len(true)
529 packedTrue = struct.pack(trueFormat, *true)
530 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000531
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000532 self.assertEqual(len(true), len(unpackedTrue))
533 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000534
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000535 for t in unpackedFalse:
536 self.assertFalse(t)
537 for t in unpackedTrue:
538 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000539
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000540 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000541
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000542 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000543
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000544 if len(packed) != 1:
545 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
546 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000547
Mark Dickinson94628ee2010-07-12 20:03:24 +0000548 try:
549 struct.pack(prefix + '?', ExplodingBool())
550 except IOError:
551 pass
552 else:
553 self.fail("Expected IOError: struct.pack(%r, "
554 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000555
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000556 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
557 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000558
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000559 def test_count_overflow(self):
560 hugecount = '{}b'.format(sys.maxsize+1)
561 self.assertRaises(struct.error, struct.calcsize, hugecount)
562
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000563 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
564 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000565
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000566 if IS32BIT:
567 def test_crasher(self):
568 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
569
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000570 def test_trailing_counter(self):
571 store = array.array('b', b' '*100)
572
573 # format lists containing only count spec should result in an error
574 self.assertRaises(struct.error, struct.pack, '12345')
575 self.assertRaises(struct.error, struct.unpack, '12345', '')
576 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
577 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
578
579 # Format lists with trailing count spec should result in an error
580 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
581 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
582 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
583 'x')
584 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
585 0)
586
587 # Mixed format tests
588 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
589 self.assertRaises(struct.error, struct.unpack, '14s42',
590 'spam and eggs')
591 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
592 'spam and eggs')
593 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
594
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000595 def test_Struct_reinitialization(self):
596 # Issue 9422: there was a memory leak when reinitializing a
597 # Struct instance. This test can be used to detect the leak
598 # when running with regrtest -L.
599 s = struct.Struct('i')
600 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000601
Meador Inge90bc2dbc2012-07-28 22:16:39 -0500602 @cpython_only
603 def test__sizeof__(self):
604 for code in integer_codes:
605 self.check_sizeof(code, 1)
606 self.check_sizeof('BHILfdspP', 9)
607 self.check_sizeof('B' * 1234, 1234)
608 self.check_sizeof('fd', 2)
609 self.check_sizeof('xxxxxxxxxxxxxx', 0)
610 self.check_sizeof('100H', 100)
611 self.check_sizeof('187s', 1)
612 self.check_sizeof('20p', 1)
613 self.check_sizeof('0s', 1)
614 self.check_sizeof('0c', 0)
Meador Ingeb14d8c92012-07-23 10:01:29 -0500615
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000616def test_main():
617 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000618
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000619if __name__ == '__main__':
620 test_main()