blob: dcc73ab8983201d02c36d22c778f88312408e2b0 [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
Martin v. Löwis33f79972012-07-29 16:33:05 +02006from test import support
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
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000011integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
12byteorders = '', '@', '=', '<', '>', '!'
13
14# Native 'q' packing isn't available on systems that don't have the C
15# long long type.
16try:
17 struct.pack('q', 5)
18except struct.error:
19 HAVE_LONG_LONG = False
20else:
21 HAVE_LONG_LONG = True
22
Tim Peters17e17d42001-06-13 22:45:27 +000023def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000024 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000025
26def bigendian_to_native(value):
27 if ISBIGENDIAN:
28 return value
29 else:
30 return string_reverse(value)
31
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000032class StructTest(unittest.TestCase):
Meador Inge90bc2dbc2012-07-28 22:16:39 -050033
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000034 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000035 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000036
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000037 def test_consistence(self):
38 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000039
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000040 sz = struct.calcsize('i')
41 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000042
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 fmt = 'cbxxxxxxhhhhiillffd?'
44 fmt3 = '3c3b18x12h6i6l6f3d3?'
45 sz = struct.calcsize(fmt)
46 sz3 = struct.calcsize(fmt3)
47 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000048
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000049 self.assertRaises(struct.error, struct.pack, 'iii', 3)
50 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000051 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
52 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000053 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
54 s = struct.pack('ii', 1, 2)
55 self.assertRaises(struct.error, struct.unpack, 'iii', s)
56 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000058 def test_transitiveness(self):
59 c = b'a'
60 b = 1
61 h = 255
62 i = 65535
63 l = 65536
64 f = 3.1415
65 d = 3.1415
66 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000067
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000068 for prefix in ('', '@', '<', '>', '=', '!'):
69 for format in ('xcbhilfd?', 'xcBHILfd?'):
70 format = prefix + format
71 s = struct.pack(format, c, b, h, i, l, f, d, t)
72 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
73 self.assertEqual(cp, c)
74 self.assertEqual(bp, b)
75 self.assertEqual(hp, h)
76 self.assertEqual(ip, i)
77 self.assertEqual(lp, l)
78 self.assertEqual(int(100 * fp), int(100 * f))
79 self.assertEqual(int(100 * dp), int(100 * d))
80 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000081
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000082 def test_new_features(self):
83 # Test some of the new features in detail
84 # (format, argument, big-endian result, little-endian result, asymmetric)
85 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +000086 ('c', b'a', b'a', b'a', 0),
87 ('xc', b'a', b'\0a', b'\0a', 0),
88 ('cx', b'a', b'a\0', b'a\0', 0),
89 ('s', b'a', b'a', b'a', 0),
90 ('0s', b'helloworld', b'', b'', 1),
91 ('1s', b'helloworld', b'h', b'h', 1),
92 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
93 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
94 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
95 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
96 ('b', 7, b'\7', b'\7', 0),
97 ('b', -7, b'\371', b'\371', 0),
98 ('B', 7, b'\7', b'\7', 0),
99 ('B', 249, b'\371', b'\371', 0),
100 ('h', 700, b'\002\274', b'\274\002', 0),
101 ('h', -700, b'\375D', b'D\375', 0),
102 ('H', 700, b'\002\274', b'\274\002', 0),
103 ('H', 0x10000-700, b'\375D', b'D\375', 0),
104 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
105 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
106 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
107 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
108 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
109 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
110 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
111 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
112 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
113 ('d', 2.0, b'@\000\000\000\000\000\000\000',
114 b'\000\000\000\000\000\000\000@', 0),
115 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
116 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
117 b'\000\000\000\000\000\000\000\300', 0),
118 ('?', 0, b'\0', b'\0', 0),
119 ('?', 3, b'\1', b'\1', 1),
120 ('?', True, b'\1', b'\1', 0),
121 ('?', [], b'\0', b'\0', 1),
122 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000123 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000124
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000125 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000126 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
127 ('='+fmt, ISBIGENDIAN and big or lil)]:
128 res = struct.pack(xfmt, arg)
129 self.assertEqual(res, exp)
130 self.assertEqual(struct.calcsize(xfmt), len(res))
131 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000132 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000133 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000134
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000135 def test_calcsize(self):
136 expected_size = {
137 'b': 1, 'B': 1,
138 'h': 2, 'H': 2,
139 'i': 4, 'I': 4,
140 'l': 4, 'L': 4,
141 'q': 8, 'Q': 8,
142 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000143
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000144 # standard integer sizes
145 for code in integer_codes:
146 for byteorder in '=', '<', '>', '!':
147 format = byteorder+code
148 size = struct.calcsize(format)
149 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000150
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000151 # native integer sizes
152 native_pairs = 'bB', 'hH', 'iI', 'lL'
153 if HAVE_LONG_LONG:
154 native_pairs += 'qQ',
155 for format_pair in native_pairs:
156 for byteorder in '', '@':
157 signed_size = struct.calcsize(byteorder + format_pair[0])
158 unsigned_size = struct.calcsize(byteorder + format_pair[1])
159 self.assertEqual(signed_size, unsigned_size)
160
161 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000162 self.assertEqual(struct.calcsize('b'), 1)
163 self.assertLessEqual(2, struct.calcsize('h'))
164 self.assertLessEqual(4, struct.calcsize('l'))
165 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
166 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000167 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000168 self.assertLessEqual(8, struct.calcsize('q'))
169 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000170
171 def test_integers(self):
172 # Integer tests (bBhHiIlLqQ).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000173 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000174
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000175 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000176 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000177 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000178 self.format = format
179 self.code = format[-1]
180 self.byteorder = format[:-1]
181 if not self.byteorder in byteorders:
182 raise ValueError("unrecognized packing byteorder: %s" %
183 self.byteorder)
184 self.bytesize = struct.calcsize(format)
185 self.bitsize = self.bytesize * 8
186 if self.code in tuple('bhilq'):
187 self.signed = True
188 self.min_value = -(2**(self.bitsize-1))
189 self.max_value = 2**(self.bitsize-1) - 1
190 elif self.code in tuple('BHILQ'):
191 self.signed = False
192 self.min_value = 0
193 self.max_value = 2**self.bitsize - 1
194 else:
195 raise ValueError("unrecognized format code: %s" %
196 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000197
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000198 def test_one(self, x, pack=struct.pack,
199 unpack=struct.unpack,
200 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000201
202 format = self.format
203 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000204 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000205 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000206 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000207 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000208 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000209 if len(expected) & 1:
210 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000211 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000212 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000213 expected = (b"\x00" * (self.bytesize - len(expected)) +
214 expected)
215 if (self.byteorder == '<' or
216 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
217 expected = string_reverse(expected)
218 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000219
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000220 # Pack work?
221 got = pack(format, x)
222 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 # Unpack work?
225 retrieved = unpack(format, got)[0]
226 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000229 self.assertRaises((struct.error, TypeError), unpack, format,
230 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000231 else:
232 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000233 self.assertRaises((OverflowError, ValueError, struct.error),
234 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000235
236 def run(self):
237 from random import randrange
238
239 # Create all interesting powers of 2.
240 values = []
241 for exp in range(self.bitsize + 3):
242 values.append(1 << exp)
243
244 # Add some random values.
245 for i in range(self.bitsize):
246 val = 0
247 for j in range(self.bytesize):
248 val = (val << 8) | randrange(256)
249 values.append(val)
250
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000251 # Values absorbed from other tests
252 values.extend([300, 700000, sys.maxsize*4])
253
254 # Try all those, and their negations, and +-1 from
255 # them. Note that this tests all power-of-2
256 # boundaries in range, and a few out of range, plus
257 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000258 for base in values:
259 for val in -base, base:
260 for incr in -1, 0, 1:
261 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000262 self.test_one(x)
263
264 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000265 class NotAnInt:
266 def __int__(self):
267 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268
Mark Dickinsone9493a12010-04-04 08:52:51 +0000269 # Objects with an '__index__' method should be allowed
270 # to pack as integers. That is assuming the implemented
271 # '__index__' method returns and 'int' or 'long'.
272 class Indexable(object):
273 def __init__(self, value):
274 self._value = value
275
276 def __index__(self):
277 return self._value
278
279 # If the '__index__' method raises a type error, then
280 # '__int__' should be used with a deprecation warning.
281 class BadIndex(object):
282 def __index__(self):
283 raise TypeError
284
285 def __int__(self):
286 return 42
287
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000288 self.assertRaises((TypeError, struct.error),
289 struct.pack, self.format,
290 "a string")
291 self.assertRaises((TypeError, struct.error),
292 struct.pack, self.format,
293 randrange)
294 self.assertRaises((TypeError, struct.error),
295 struct.pack, self.format,
296 3+42j)
297 self.assertRaises((TypeError, struct.error),
298 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000299 NotAnInt())
300 self.assertRaises((TypeError, struct.error),
301 struct.pack, self.format,
302 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000303
Mark Dickinsone9493a12010-04-04 08:52:51 +0000304 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000305 for obj in (Indexable(0), Indexable(10), Indexable(17),
306 Indexable(42), Indexable(100), Indexable(127)):
307 try:
308 struct.pack(format, obj)
309 except:
310 self.fail("integer code pack failed on object "
311 "with '__index__' method")
312
Mark Dickinsone9493a12010-04-04 08:52:51 +0000313 # Check for bogus values from '__index__'.
314 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
315 Indexable({'a': 1}), Indexable([1, 2, 3])):
316 self.assertRaises((TypeError, struct.error),
317 struct.pack, self.format,
318 obj)
319
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000320 for code in integer_codes:
321 for byteorder in byteorders:
322 if (byteorder in ('', '@') and code in ('q', 'Q') and
323 not HAVE_LONG_LONG):
324 continue
325 format = byteorder+code
326 t = IntTester(format)
327 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000328
329 def test_p_code(self):
330 # Test p ("Pascal string") code.
331 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000332 ('p', b'abc', b'\x00', b''),
333 ('1p', b'abc', b'\x00', b''),
334 ('2p', b'abc', b'\x01a', b'a'),
335 ('3p', b'abc', b'\x02ab', b'ab'),
336 ('4p', b'abc', b'\x03abc', b'abc'),
337 ('5p', b'abc', b'\x03abc\x00', b'abc'),
338 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
339 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000340 got = struct.pack(code, input)
341 self.assertEqual(got, expected)
342 (got,) = struct.unpack(code, got)
343 self.assertEqual(got, expectedback)
344
345 def test_705836(self):
346 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
347 # from the low-order discarded bits could propagate into the exponent
348 # field, causing the result to be wrong by a factor of 2.
349 import math
350
351 for base in range(1, 33):
352 # smaller <- largest representable float less than base.
353 delta = 0.5
354 while base - delta / 2.0 != base:
355 delta /= 2.0
356 smaller = base - delta
357 # Packing this rounds away a solid string of trailing 1 bits.
358 packed = struct.pack("<f", smaller)
359 unpacked = struct.unpack("<f", packed)[0]
360 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
361 # 16, respectively.
362 self.assertEqual(base, unpacked)
363 bigpacked = struct.pack(">f", smaller)
364 self.assertEqual(bigpacked, string_reverse(packed))
365 unpacked = struct.unpack(">f", bigpacked)[0]
366 self.assertEqual(base, unpacked)
367
368 # Largest finite IEEE single.
369 big = (1 << 24) - 1
370 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000371 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000372 unpacked = struct.unpack(">f", packed)[0]
373 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000374
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000375 # The same, but tack on a 1 bit so it rounds up to infinity.
376 big = (1 << 25) - 1
377 big = math.ldexp(big, 127 - 24)
378 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000379
Mark Dickinsonea835e72009-04-19 20:40:33 +0000380 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000381 for byteorder in '', '@', '=', '<', '>', '!':
382 for code in integer_codes:
383 if (byteorder in ('', '@') and code in ('q', 'Q') and
384 not HAVE_LONG_LONG):
385 continue
386 format = byteorder + code
387 self.assertRaises(struct.error, struct.pack, format, 1.0)
388 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000389 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
390 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
391
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000392 def test_unpack_from(self):
393 test_string = b'abcd01234'
394 fmt = '4s'
395 s = struct.Struct(fmt)
396 for cls in (bytes, bytearray):
397 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000398 self.assertEqual(s.unpack_from(data), (b'abcd',))
399 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
400 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
401 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000402 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000403 for i in range(6, len(test_string) + 1):
404 self.assertRaises(struct.error, s.unpack_from, data, i)
405 for cls in (bytes, bytearray):
406 data = cls(test_string)
407 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
408 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
409 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
410 for i in range(6):
411 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
412 for i in range(6, len(test_string) + 1):
413 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000414
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000415 def test_pack_into(self):
416 test_string = b'Reykjavik rocks, eow!'
417 writable_buf = array.array('b', b' '*100)
418 fmt = '21s'
419 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000420
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000421 # Test without offset
422 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000423 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000424 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000425
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000426 # Test with offset.
427 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000428 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000429 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000430
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000431 # Go beyond boundaries.
432 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000433 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
434 test_string)
435 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
436 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000437
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000438 # Test bogus offset (issue 3694)
439 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000440 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
441 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000442
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000443 def test_pack_into_fn(self):
444 test_string = b'Reykjavik rocks, eow!'
445 writable_buf = array.array('b', b' '*100)
446 fmt = '21s'
447 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000448
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000449 # Test without offset.
450 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000451 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000452 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000453
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000454 # Test with offset.
455 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000456 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000457 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000458
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000459 # Go beyond boundaries.
460 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000461 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
462 test_string)
463 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
464 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200467 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000468 data1 = array.array('B', b'\x12\x34\x56\x78')
469 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
470 for data in [data1, data2]:
471 value, = struct.unpack('>I', data)
472 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000473
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000474 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000475 class ExplodingBool(object):
476 def __bool__(self):
477 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000478 for prefix in tuple("<>!=")+('',):
479 false = (), [], [], '', 0
480 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000481
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000482 falseFormat = prefix + '?' * len(false)
483 packedFalse = struct.pack(falseFormat, *false)
484 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000485
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000486 trueFormat = prefix + '?' * len(true)
487 packedTrue = struct.pack(trueFormat, *true)
488 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000489
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000490 self.assertEqual(len(true), len(unpackedTrue))
491 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000493 for t in unpackedFalse:
494 self.assertFalse(t)
495 for t in unpackedTrue:
496 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000497
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000498 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000500 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 if len(packed) != 1:
503 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
504 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000505
Mark Dickinson94628ee2010-07-12 20:03:24 +0000506 try:
507 struct.pack(prefix + '?', ExplodingBool())
508 except IOError:
509 pass
510 else:
511 self.fail("Expected IOError: struct.pack(%r, "
512 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000513
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000514 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
515 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000516
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000517 def test_count_overflow(self):
518 hugecount = '{}b'.format(sys.maxsize+1)
519 self.assertRaises(struct.error, struct.calcsize, hugecount)
520
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000521 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
522 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000523
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000524 if IS32BIT:
525 def test_crasher(self):
526 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
527
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000528 def test_trailing_counter(self):
529 store = array.array('b', b' '*100)
530
531 # format lists containing only count spec should result in an error
532 self.assertRaises(struct.error, struct.pack, '12345')
533 self.assertRaises(struct.error, struct.unpack, '12345', '')
534 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
535 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
536
537 # Format lists with trailing count spec should result in an error
538 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
539 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
540 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
541 'x')
542 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
543 0)
544
545 # Mixed format tests
546 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
547 self.assertRaises(struct.error, struct.unpack, '14s42',
548 'spam and eggs')
549 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
550 'spam and eggs')
551 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
552
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000553 def test_Struct_reinitialization(self):
554 # Issue 9422: there was a memory leak when reinitializing a
555 # Struct instance. This test can be used to detect the leak
556 # when running with regrtest -L.
557 s = struct.Struct('i')
558 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000559
Martin v. Löwis33f79972012-07-29 16:33:05 +0200560 def check_sizeof(self, format_str, number_of_codes):
561 # The size of 'PyStructObject'
562 totalsize = support.calcobjsize('5P')
563 # The size taken up by the 'formatcode' dynamic array
564 totalsize += struct.calcsize('3P') * (number_of_codes + 1)
565 support.check_sizeof(self, struct.Struct(format_str), totalsize)
566
567 @support.cpython_only
Meador Inge90bc2dbc2012-07-28 22:16:39 -0500568 def test__sizeof__(self):
569 for code in integer_codes:
570 self.check_sizeof(code, 1)
571 self.check_sizeof('BHILfdspP', 9)
572 self.check_sizeof('B' * 1234, 1234)
573 self.check_sizeof('fd', 2)
574 self.check_sizeof('xxxxxxxxxxxxxx', 0)
575 self.check_sizeof('100H', 100)
576 self.check_sizeof('187s', 1)
577 self.check_sizeof('20p', 1)
578 self.check_sizeof('0s', 1)
579 self.check_sizeof('0c', 0)
Meador Ingeb14d8c92012-07-23 10:01:29 -0500580
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000581def test_main():
Martin v. Löwis33f79972012-07-29 16:33:05 +0200582 support.run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000583
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000584if __name__ == '__main__':
585 test_main()