blob: b77982ea5923f57166f2de10969583df59067b8c [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
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 def setUp(self):
34 # due to missing size_t information from struct, it is assumed that
35 # sizeof(Py_ssize_t) = sizeof(void*)
36 self.header = 'PP'
37 if hasattr(sys, "gettotalrefcount"):
38 self.header += '2P'
39
40 def check_sizeof(self, format_str, number_of_codes):
41 def size(fmt):
42 """Wrapper around struct.calcsize which enforces the alignment
43 of the end of a structure to the alignment requirement of pointer.
44
45 Note: This wrapper should only be used if a pointer member is
46 included and no member with a size larger than a pointer exists.
47 """
48 return struct.calcsize(fmt + '0P')
49
50 struct_obj = struct.Struct(format_str)
51 # The size of 'PyStructObject'
52 totalsize = size(self.header + '5P')
53 # The size taken up by the 'formatcode' dynamic array
54 totalsize += size('3P') * (number_of_codes + 1)
55 result = sys.getsizeof(struct_obj)
56 msg = 'wrong size for %s: got %d, expected %d' \
57 % (type(struct_obj), result, totalsize)
58 self.assertEqual(result, totalsize, msg)
59
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000060 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000061 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000062
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000063 def test_consistence(self):
64 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000065
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000066 sz = struct.calcsize('i')
67 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000068
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000069 fmt = 'cbxxxxxxhhhhiillffd?'
70 fmt3 = '3c3b18x12h6i6l6f3d3?'
71 sz = struct.calcsize(fmt)
72 sz3 = struct.calcsize(fmt3)
73 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000074
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000075 self.assertRaises(struct.error, struct.pack, 'iii', 3)
76 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000077 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
78 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000079 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
80 s = struct.pack('ii', 1, 2)
81 self.assertRaises(struct.error, struct.unpack, 'iii', s)
82 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000083
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000084 def test_transitiveness(self):
85 c = b'a'
86 b = 1
87 h = 255
88 i = 65535
89 l = 65536
90 f = 3.1415
91 d = 3.1415
92 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000093
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000094 for prefix in ('', '@', '<', '>', '=', '!'):
95 for format in ('xcbhilfd?', 'xcBHILfd?'):
96 format = prefix + format
97 s = struct.pack(format, c, b, h, i, l, f, d, t)
98 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
99 self.assertEqual(cp, c)
100 self.assertEqual(bp, b)
101 self.assertEqual(hp, h)
102 self.assertEqual(ip, i)
103 self.assertEqual(lp, l)
104 self.assertEqual(int(100 * fp), int(100 * f))
105 self.assertEqual(int(100 * dp), int(100 * d))
106 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000107
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000108 def test_new_features(self):
109 # Test some of the new features in detail
110 # (format, argument, big-endian result, little-endian result, asymmetric)
111 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000112 ('c', b'a', b'a', b'a', 0),
113 ('xc', b'a', b'\0a', b'\0a', 0),
114 ('cx', b'a', b'a\0', b'a\0', 0),
115 ('s', b'a', b'a', b'a', 0),
116 ('0s', b'helloworld', b'', b'', 1),
117 ('1s', b'helloworld', b'h', b'h', 1),
118 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
119 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
120 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
121 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
122 ('b', 7, b'\7', b'\7', 0),
123 ('b', -7, b'\371', b'\371', 0),
124 ('B', 7, b'\7', b'\7', 0),
125 ('B', 249, b'\371', b'\371', 0),
126 ('h', 700, b'\002\274', b'\274\002', 0),
127 ('h', -700, b'\375D', b'D\375', 0),
128 ('H', 700, b'\002\274', b'\274\002', 0),
129 ('H', 0x10000-700, b'\375D', b'D\375', 0),
130 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
131 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
132 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
133 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
134 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
135 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
136 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
137 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
138 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
139 ('d', 2.0, b'@\000\000\000\000\000\000\000',
140 b'\000\000\000\000\000\000\000@', 0),
141 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
142 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
143 b'\000\000\000\000\000\000\000\300', 0),
144 ('?', 0, b'\0', b'\0', 0),
145 ('?', 3, b'\1', b'\1', 1),
146 ('?', True, b'\1', b'\1', 0),
147 ('?', [], b'\0', b'\0', 1),
148 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000149 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000150
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000151 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000152 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
153 ('='+fmt, ISBIGENDIAN and big or lil)]:
154 res = struct.pack(xfmt, arg)
155 self.assertEqual(res, exp)
156 self.assertEqual(struct.calcsize(xfmt), len(res))
157 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000158 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000159 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000160
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000161 def test_calcsize(self):
162 expected_size = {
163 'b': 1, 'B': 1,
164 'h': 2, 'H': 2,
165 'i': 4, 'I': 4,
166 'l': 4, 'L': 4,
167 'q': 8, 'Q': 8,
168 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000169
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000170 # standard integer sizes
171 for code in integer_codes:
172 for byteorder in '=', '<', '>', '!':
173 format = byteorder+code
174 size = struct.calcsize(format)
175 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000176
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000177 # native integer sizes
178 native_pairs = 'bB', 'hH', 'iI', 'lL'
179 if HAVE_LONG_LONG:
180 native_pairs += 'qQ',
181 for format_pair in native_pairs:
182 for byteorder in '', '@':
183 signed_size = struct.calcsize(byteorder + format_pair[0])
184 unsigned_size = struct.calcsize(byteorder + format_pair[1])
185 self.assertEqual(signed_size, unsigned_size)
186
187 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000188 self.assertEqual(struct.calcsize('b'), 1)
189 self.assertLessEqual(2, struct.calcsize('h'))
190 self.assertLessEqual(4, struct.calcsize('l'))
191 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
192 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000193 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000194 self.assertLessEqual(8, struct.calcsize('q'))
195 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000196
197 def test_integers(self):
198 # Integer tests (bBhHiIlLqQ).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000199 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000200
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000201 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000202 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000203 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000204 self.format = format
205 self.code = format[-1]
206 self.byteorder = format[:-1]
207 if not self.byteorder in byteorders:
208 raise ValueError("unrecognized packing byteorder: %s" %
209 self.byteorder)
210 self.bytesize = struct.calcsize(format)
211 self.bitsize = self.bytesize * 8
212 if self.code in tuple('bhilq'):
213 self.signed = True
214 self.min_value = -(2**(self.bitsize-1))
215 self.max_value = 2**(self.bitsize-1) - 1
216 elif self.code in tuple('BHILQ'):
217 self.signed = False
218 self.min_value = 0
219 self.max_value = 2**self.bitsize - 1
220 else:
221 raise ValueError("unrecognized format code: %s" %
222 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 def test_one(self, x, pack=struct.pack,
225 unpack=struct.unpack,
226 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000227
228 format = self.format
229 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000230 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000231 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000232 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000233 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000234 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000235 if len(expected) & 1:
236 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000237 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000238 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000239 expected = (b"\x00" * (self.bytesize - len(expected)) +
240 expected)
241 if (self.byteorder == '<' or
242 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
243 expected = string_reverse(expected)
244 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000245
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000246 # Pack work?
247 got = pack(format, x)
248 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000249
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000250 # Unpack work?
251 retrieved = unpack(format, got)[0]
252 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000253
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000254 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000255 self.assertRaises((struct.error, TypeError), unpack, format,
256 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000257 else:
258 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000259 self.assertRaises((OverflowError, ValueError, struct.error),
260 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000261
262 def run(self):
263 from random import randrange
264
265 # Create all interesting powers of 2.
266 values = []
267 for exp in range(self.bitsize + 3):
268 values.append(1 << exp)
269
270 # Add some random values.
271 for i in range(self.bitsize):
272 val = 0
273 for j in range(self.bytesize):
274 val = (val << 8) | randrange(256)
275 values.append(val)
276
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000277 # Values absorbed from other tests
278 values.extend([300, 700000, sys.maxsize*4])
279
280 # Try all those, and their negations, and +-1 from
281 # them. Note that this tests all power-of-2
282 # boundaries in range, and a few out of range, plus
283 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000284 for base in values:
285 for val in -base, base:
286 for incr in -1, 0, 1:
287 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000288 self.test_one(x)
289
290 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000291 class NotAnInt:
292 def __int__(self):
293 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000294
Mark Dickinsone9493a12010-04-04 08:52:51 +0000295 # Objects with an '__index__' method should be allowed
296 # to pack as integers. That is assuming the implemented
297 # '__index__' method returns and 'int' or 'long'.
298 class Indexable(object):
299 def __init__(self, value):
300 self._value = value
301
302 def __index__(self):
303 return self._value
304
305 # If the '__index__' method raises a type error, then
306 # '__int__' should be used with a deprecation warning.
307 class BadIndex(object):
308 def __index__(self):
309 raise TypeError
310
311 def __int__(self):
312 return 42
313
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000314 self.assertRaises((TypeError, struct.error),
315 struct.pack, self.format,
316 "a string")
317 self.assertRaises((TypeError, struct.error),
318 struct.pack, self.format,
319 randrange)
320 self.assertRaises((TypeError, struct.error),
321 struct.pack, self.format,
322 3+42j)
323 self.assertRaises((TypeError, struct.error),
324 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000325 NotAnInt())
326 self.assertRaises((TypeError, struct.error),
327 struct.pack, self.format,
328 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000329
Mark Dickinsone9493a12010-04-04 08:52:51 +0000330 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000331 for obj in (Indexable(0), Indexable(10), Indexable(17),
332 Indexable(42), Indexable(100), Indexable(127)):
333 try:
334 struct.pack(format, obj)
335 except:
336 self.fail("integer code pack failed on object "
337 "with '__index__' method")
338
Mark Dickinsone9493a12010-04-04 08:52:51 +0000339 # Check for bogus values from '__index__'.
340 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
341 Indexable({'a': 1}), Indexable([1, 2, 3])):
342 self.assertRaises((TypeError, struct.error),
343 struct.pack, self.format,
344 obj)
345
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000346 for code in integer_codes:
347 for byteorder in byteorders:
348 if (byteorder in ('', '@') and code in ('q', 'Q') and
349 not HAVE_LONG_LONG):
350 continue
351 format = byteorder+code
352 t = IntTester(format)
353 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000354
355 def test_p_code(self):
356 # Test p ("Pascal string") code.
357 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000358 ('p', b'abc', b'\x00', b''),
359 ('1p', b'abc', b'\x00', b''),
360 ('2p', b'abc', b'\x01a', b'a'),
361 ('3p', b'abc', b'\x02ab', b'ab'),
362 ('4p', b'abc', b'\x03abc', b'abc'),
363 ('5p', b'abc', b'\x03abc\x00', b'abc'),
364 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
365 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000366 got = struct.pack(code, input)
367 self.assertEqual(got, expected)
368 (got,) = struct.unpack(code, got)
369 self.assertEqual(got, expectedback)
370
371 def test_705836(self):
372 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
373 # from the low-order discarded bits could propagate into the exponent
374 # field, causing the result to be wrong by a factor of 2.
375 import math
376
377 for base in range(1, 33):
378 # smaller <- largest representable float less than base.
379 delta = 0.5
380 while base - delta / 2.0 != base:
381 delta /= 2.0
382 smaller = base - delta
383 # Packing this rounds away a solid string of trailing 1 bits.
384 packed = struct.pack("<f", smaller)
385 unpacked = struct.unpack("<f", packed)[0]
386 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
387 # 16, respectively.
388 self.assertEqual(base, unpacked)
389 bigpacked = struct.pack(">f", smaller)
390 self.assertEqual(bigpacked, string_reverse(packed))
391 unpacked = struct.unpack(">f", bigpacked)[0]
392 self.assertEqual(base, unpacked)
393
394 # Largest finite IEEE single.
395 big = (1 << 24) - 1
396 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000397 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000398 unpacked = struct.unpack(">f", packed)[0]
399 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000400
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000401 # The same, but tack on a 1 bit so it rounds up to infinity.
402 big = (1 << 25) - 1
403 big = math.ldexp(big, 127 - 24)
404 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000405
Mark Dickinsonea835e72009-04-19 20:40:33 +0000406 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000407 for byteorder in '', '@', '=', '<', '>', '!':
408 for code in integer_codes:
409 if (byteorder in ('', '@') and code in ('q', 'Q') and
410 not HAVE_LONG_LONG):
411 continue
412 format = byteorder + code
413 self.assertRaises(struct.error, struct.pack, format, 1.0)
414 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000415 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
416 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
417
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000418 def test_unpack_from(self):
419 test_string = b'abcd01234'
420 fmt = '4s'
421 s = struct.Struct(fmt)
422 for cls in (bytes, bytearray):
423 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000424 self.assertEqual(s.unpack_from(data), (b'abcd',))
425 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
426 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
427 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000428 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000429 for i in range(6, len(test_string) + 1):
430 self.assertRaises(struct.error, s.unpack_from, data, i)
431 for cls in (bytes, bytearray):
432 data = cls(test_string)
433 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
434 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
435 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
436 for i in range(6):
437 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
438 for i in range(6, len(test_string) + 1):
439 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000440
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000441 def test_pack_into(self):
442 test_string = b'Reykjavik rocks, eow!'
443 writable_buf = array.array('b', b' '*100)
444 fmt = '21s'
445 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000446
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000447 # Test without offset
448 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000449 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000450 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000451
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000452 # Test with offset.
453 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000454 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000455 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000456
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000457 # Go beyond boundaries.
458 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000459 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
460 test_string)
461 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
462 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000463
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000464 # Test bogus offset (issue 3694)
465 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000466 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
467 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000468
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000469 def test_pack_into_fn(self):
470 test_string = b'Reykjavik rocks, eow!'
471 writable_buf = array.array('b', b' '*100)
472 fmt = '21s'
473 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000474
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000475 # Test without offset.
476 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000477 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000478 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000479
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000480 # Test with offset.
481 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000482 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000483 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000484
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 # Go beyond boundaries.
486 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000487 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
488 test_string)
489 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
490 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000491
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000492 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200493 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000494 data1 = array.array('B', b'\x12\x34\x56\x78')
495 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
496 for data in [data1, data2]:
497 value, = struct.unpack('>I', data)
498 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000500 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000501 class ExplodingBool(object):
502 def __bool__(self):
503 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000504 for prefix in tuple("<>!=")+('',):
505 false = (), [], [], '', 0
506 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000507
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000508 falseFormat = prefix + '?' * len(false)
509 packedFalse = struct.pack(falseFormat, *false)
510 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 trueFormat = prefix + '?' * len(true)
513 packedTrue = struct.pack(trueFormat, *true)
514 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000515
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000516 self.assertEqual(len(true), len(unpackedTrue))
517 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000518
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000519 for t in unpackedFalse:
520 self.assertFalse(t)
521 for t in unpackedTrue:
522 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000523
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000524 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000525
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000526 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000527
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000528 if len(packed) != 1:
529 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
530 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000531
Mark Dickinson94628ee2010-07-12 20:03:24 +0000532 try:
533 struct.pack(prefix + '?', ExplodingBool())
534 except IOError:
535 pass
536 else:
537 self.fail("Expected IOError: struct.pack(%r, "
538 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000539
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000540 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
541 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000542
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000543 def test_count_overflow(self):
544 hugecount = '{}b'.format(sys.maxsize+1)
545 self.assertRaises(struct.error, struct.calcsize, hugecount)
546
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000547 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
548 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000549
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000550 if IS32BIT:
551 def test_crasher(self):
552 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
553
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000554 def test_trailing_counter(self):
555 store = array.array('b', b' '*100)
556
557 # format lists containing only count spec should result in an error
558 self.assertRaises(struct.error, struct.pack, '12345')
559 self.assertRaises(struct.error, struct.unpack, '12345', '')
560 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
561 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
562
563 # Format lists with trailing count spec should result in an error
564 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
565 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
566 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
567 'x')
568 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
569 0)
570
571 # Mixed format tests
572 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
573 self.assertRaises(struct.error, struct.unpack, '14s42',
574 'spam and eggs')
575 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
576 'spam and eggs')
577 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
578
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000579 def test_Struct_reinitialization(self):
580 # Issue 9422: there was a memory leak when reinitializing a
581 # Struct instance. This test can be used to detect the leak
582 # when running with regrtest -L.
583 s = struct.Struct('i')
584 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000585
Meador Inge90bc2dbc2012-07-28 22:16:39 -0500586 @cpython_only
587 def test__sizeof__(self):
588 for code in integer_codes:
589 self.check_sizeof(code, 1)
590 self.check_sizeof('BHILfdspP', 9)
591 self.check_sizeof('B' * 1234, 1234)
592 self.check_sizeof('fd', 2)
593 self.check_sizeof('xxxxxxxxxxxxxx', 0)
594 self.check_sizeof('100H', 100)
595 self.check_sizeof('187s', 1)
596 self.check_sizeof('20p', 1)
597 self.check_sizeof('0s', 1)
598 self.check_sizeof('0c', 0)
Meador Ingeb14d8c92012-07-23 10:01:29 -0500599
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000600def test_main():
601 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000602
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000603if __name__ == '__main__':
604 test_main()