blob: 2ccaad29c08fb2ad489282245a3afb1242d8361c [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
6from test.support import run_unittest
7
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):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000033 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000034 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000035
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000036 def test_consistence(self):
37 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000038
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 sz = struct.calcsize('i')
40 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000041
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000042 fmt = 'cbxxxxxxhhhhiillffd?'
43 fmt3 = '3c3b18x12h6i6l6f3d3?'
44 sz = struct.calcsize(fmt)
45 sz3 = struct.calcsize(fmt3)
46 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000047
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000048 self.assertRaises(struct.error, struct.pack, 'iii', 3)
49 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000050 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
51 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000052 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
53 s = struct.pack('ii', 1, 2)
54 self.assertRaises(struct.error, struct.unpack, 'iii', s)
55 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000056
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000057 def test_transitiveness(self):
58 c = b'a'
59 b = 1
60 h = 255
61 i = 65535
62 l = 65536
63 f = 3.1415
64 d = 3.1415
65 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000066
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000067 for prefix in ('', '@', '<', '>', '=', '!'):
68 for format in ('xcbhilfd?', 'xcBHILfd?'):
69 format = prefix + format
70 s = struct.pack(format, c, b, h, i, l, f, d, t)
71 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
72 self.assertEqual(cp, c)
73 self.assertEqual(bp, b)
74 self.assertEqual(hp, h)
75 self.assertEqual(ip, i)
76 self.assertEqual(lp, l)
77 self.assertEqual(int(100 * fp), int(100 * f))
78 self.assertEqual(int(100 * dp), int(100 * d))
79 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000080
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000081 def test_new_features(self):
82 # Test some of the new features in detail
83 # (format, argument, big-endian result, little-endian result, asymmetric)
84 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +000085 ('c', b'a', b'a', b'a', 0),
86 ('xc', b'a', b'\0a', b'\0a', 0),
87 ('cx', b'a', b'a\0', b'a\0', 0),
88 ('s', b'a', b'a', b'a', 0),
89 ('0s', b'helloworld', b'', b'', 1),
90 ('1s', b'helloworld', b'h', b'h', 1),
91 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
92 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
93 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
94 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
95 ('b', 7, b'\7', b'\7', 0),
96 ('b', -7, b'\371', b'\371', 0),
97 ('B', 7, b'\7', b'\7', 0),
98 ('B', 249, b'\371', b'\371', 0),
99 ('h', 700, b'\002\274', b'\274\002', 0),
100 ('h', -700, b'\375D', b'D\375', 0),
101 ('H', 700, b'\002\274', b'\274\002', 0),
102 ('H', 0x10000-700, b'\375D', b'D\375', 0),
103 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
104 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
105 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
106 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
107 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
108 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
109 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
110 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
111 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
112 ('d', 2.0, b'@\000\000\000\000\000\000\000',
113 b'\000\000\000\000\000\000\000@', 0),
114 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
115 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
116 b'\000\000\000\000\000\000\000\300', 0),
117 ('?', 0, b'\0', b'\0', 0),
118 ('?', 3, b'\1', b'\1', 1),
119 ('?', True, b'\1', b'\1', 0),
120 ('?', [], b'\0', b'\0', 1),
121 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000122 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000123
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000124 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000125 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
126 ('='+fmt, ISBIGENDIAN and big or lil)]:
127 res = struct.pack(xfmt, arg)
128 self.assertEqual(res, exp)
129 self.assertEqual(struct.calcsize(xfmt), len(res))
130 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000131 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000132 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000133
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000134 def test_calcsize(self):
135 expected_size = {
136 'b': 1, 'B': 1,
137 'h': 2, 'H': 2,
138 'i': 4, 'I': 4,
139 'l': 4, 'L': 4,
140 'q': 8, 'Q': 8,
141 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000142
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000143 # standard integer sizes
144 for code in integer_codes:
145 for byteorder in '=', '<', '>', '!':
146 format = byteorder+code
147 size = struct.calcsize(format)
148 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000149
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000150 # native integer sizes
151 native_pairs = 'bB', 'hH', 'iI', 'lL'
152 if HAVE_LONG_LONG:
153 native_pairs += 'qQ',
154 for format_pair in native_pairs:
155 for byteorder in '', '@':
156 signed_size = struct.calcsize(byteorder + format_pair[0])
157 unsigned_size = struct.calcsize(byteorder + format_pair[1])
158 self.assertEqual(signed_size, unsigned_size)
159
160 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000161 self.assertEqual(struct.calcsize('b'), 1)
162 self.assertLessEqual(2, struct.calcsize('h'))
163 self.assertLessEqual(4, struct.calcsize('l'))
164 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
165 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000166 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000167 self.assertLessEqual(8, struct.calcsize('q'))
168 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000169
170 def test_integers(self):
171 # Integer tests (bBhHiIlLqQ).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000172 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000173
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000174 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000175 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000176 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000177 self.format = format
178 self.code = format[-1]
179 self.byteorder = format[:-1]
180 if not self.byteorder in byteorders:
181 raise ValueError("unrecognized packing byteorder: %s" %
182 self.byteorder)
183 self.bytesize = struct.calcsize(format)
184 self.bitsize = self.bytesize * 8
185 if self.code in tuple('bhilq'):
186 self.signed = True
187 self.min_value = -(2**(self.bitsize-1))
188 self.max_value = 2**(self.bitsize-1) - 1
189 elif self.code in tuple('BHILQ'):
190 self.signed = False
191 self.min_value = 0
192 self.max_value = 2**self.bitsize - 1
193 else:
194 raise ValueError("unrecognized format code: %s" %
195 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000196
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000197 def test_one(self, x, pack=struct.pack,
198 unpack=struct.unpack,
199 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000200
201 format = self.format
202 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000203 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000204 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000205 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000206 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000207 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000208 if len(expected) & 1:
209 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000210 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000211 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000212 expected = (b"\x00" * (self.bytesize - len(expected)) +
213 expected)
214 if (self.byteorder == '<' or
215 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
216 expected = string_reverse(expected)
217 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000218
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000219 # Pack work?
220 got = pack(format, x)
221 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000222
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000223 # Unpack work?
224 retrieved = unpack(format, got)[0]
225 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000226
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000227 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000228 self.assertRaises((struct.error, TypeError), unpack, format,
229 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000230 else:
231 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000232 self.assertRaises((OverflowError, ValueError, struct.error),
233 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000234
235 def run(self):
236 from random import randrange
237
238 # Create all interesting powers of 2.
239 values = []
240 for exp in range(self.bitsize + 3):
241 values.append(1 << exp)
242
243 # Add some random values.
244 for i in range(self.bitsize):
245 val = 0
246 for j in range(self.bytesize):
247 val = (val << 8) | randrange(256)
248 values.append(val)
249
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000250 # Values absorbed from other tests
251 values.extend([300, 700000, sys.maxsize*4])
252
253 # Try all those, and their negations, and +-1 from
254 # them. Note that this tests all power-of-2
255 # boundaries in range, and a few out of range, plus
256 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000257 for base in values:
258 for val in -base, base:
259 for incr in -1, 0, 1:
260 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000261 self.test_one(x)
262
263 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000264 class NotAnInt:
265 def __int__(self):
266 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000267
Mark Dickinsone9493a12010-04-04 08:52:51 +0000268 # Objects with an '__index__' method should be allowed
269 # to pack as integers. That is assuming the implemented
270 # '__index__' method returns and 'int' or 'long'.
271 class Indexable(object):
272 def __init__(self, value):
273 self._value = value
274
275 def __index__(self):
276 return self._value
277
278 # If the '__index__' method raises a type error, then
279 # '__int__' should be used with a deprecation warning.
280 class BadIndex(object):
281 def __index__(self):
282 raise TypeError
283
284 def __int__(self):
285 return 42
286
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000287 self.assertRaises((TypeError, struct.error),
288 struct.pack, self.format,
289 "a string")
290 self.assertRaises((TypeError, struct.error),
291 struct.pack, self.format,
292 randrange)
293 self.assertRaises((TypeError, struct.error),
294 struct.pack, self.format,
295 3+42j)
296 self.assertRaises((TypeError, struct.error),
297 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000298 NotAnInt())
299 self.assertRaises((TypeError, struct.error),
300 struct.pack, self.format,
301 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000302
Mark Dickinsone9493a12010-04-04 08:52:51 +0000303 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000304 for obj in (Indexable(0), Indexable(10), Indexable(17),
305 Indexable(42), Indexable(100), Indexable(127)):
306 try:
307 struct.pack(format, obj)
308 except:
309 self.fail("integer code pack failed on object "
310 "with '__index__' method")
311
Mark Dickinsone9493a12010-04-04 08:52:51 +0000312 # Check for bogus values from '__index__'.
313 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
314 Indexable({'a': 1}), Indexable([1, 2, 3])):
315 self.assertRaises((TypeError, struct.error),
316 struct.pack, self.format,
317 obj)
318
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000319 for code in integer_codes:
320 for byteorder in byteorders:
321 if (byteorder in ('', '@') and code in ('q', 'Q') and
322 not HAVE_LONG_LONG):
323 continue
324 format = byteorder+code
325 t = IntTester(format)
326 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000327
328 def test_p_code(self):
329 # Test p ("Pascal string") code.
330 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000331 ('p', b'abc', b'\x00', b''),
332 ('1p', b'abc', b'\x00', b''),
333 ('2p', b'abc', b'\x01a', b'a'),
334 ('3p', b'abc', b'\x02ab', b'ab'),
335 ('4p', b'abc', b'\x03abc', b'abc'),
336 ('5p', b'abc', b'\x03abc\x00', b'abc'),
337 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
338 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000339 got = struct.pack(code, input)
340 self.assertEqual(got, expected)
341 (got,) = struct.unpack(code, got)
342 self.assertEqual(got, expectedback)
343
344 def test_705836(self):
345 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
346 # from the low-order discarded bits could propagate into the exponent
347 # field, causing the result to be wrong by a factor of 2.
348 import math
349
350 for base in range(1, 33):
351 # smaller <- largest representable float less than base.
352 delta = 0.5
353 while base - delta / 2.0 != base:
354 delta /= 2.0
355 smaller = base - delta
356 # Packing this rounds away a solid string of trailing 1 bits.
357 packed = struct.pack("<f", smaller)
358 unpacked = struct.unpack("<f", packed)[0]
359 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
360 # 16, respectively.
361 self.assertEqual(base, unpacked)
362 bigpacked = struct.pack(">f", smaller)
363 self.assertEqual(bigpacked, string_reverse(packed))
364 unpacked = struct.unpack(">f", bigpacked)[0]
365 self.assertEqual(base, unpacked)
366
367 # Largest finite IEEE single.
368 big = (1 << 24) - 1
369 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000370 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000371 unpacked = struct.unpack(">f", packed)[0]
372 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000373
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000374 # The same, but tack on a 1 bit so it rounds up to infinity.
375 big = (1 << 25) - 1
376 big = math.ldexp(big, 127 - 24)
377 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000378
Mark Dickinsonea835e72009-04-19 20:40:33 +0000379 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000380 for byteorder in '', '@', '=', '<', '>', '!':
381 for code in integer_codes:
382 if (byteorder in ('', '@') and code in ('q', 'Q') and
383 not HAVE_LONG_LONG):
384 continue
385 format = byteorder + code
386 self.assertRaises(struct.error, struct.pack, format, 1.0)
387 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000388 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
389 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
390
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000391 def test_unpack_from(self):
392 test_string = b'abcd01234'
393 fmt = '4s'
394 s = struct.Struct(fmt)
395 for cls in (bytes, bytearray):
396 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000397 self.assertEqual(s.unpack_from(data), (b'abcd',))
398 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
399 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
400 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000401 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000402 for i in range(6, len(test_string) + 1):
403 self.assertRaises(struct.error, s.unpack_from, data, i)
404 for cls in (bytes, bytearray):
405 data = cls(test_string)
406 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
407 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
408 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
409 for i in range(6):
410 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
411 for i in range(6, len(test_string) + 1):
412 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000413
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000414 def test_pack_into(self):
415 test_string = b'Reykjavik rocks, eow!'
416 writable_buf = array.array('b', b' '*100)
417 fmt = '21s'
418 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000419
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000420 # Test without offset
421 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000422 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000423 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000424
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000425 # Test with offset.
426 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000427 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000428 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000429
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000430 # Go beyond boundaries.
431 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000432 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
433 test_string)
434 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
435 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000436
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000437 # Test bogus offset (issue 3694)
438 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000439 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
440 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000441
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000442 def test_pack_into_fn(self):
443 test_string = b'Reykjavik rocks, eow!'
444 writable_buf = array.array('b', b' '*100)
445 fmt = '21s'
446 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 # Test without offset.
449 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000450 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000451 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000452
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000453 # Test with offset.
454 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000455 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000456 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000457
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000458 # Go beyond boundaries.
459 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000460 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
461 test_string)
462 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
463 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000464
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000465 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200466 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000467 data1 = array.array('B', b'\x12\x34\x56\x78')
468 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
469 for data in [data1, data2]:
470 value, = struct.unpack('>I', data)
471 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000472
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000473 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000474 class ExplodingBool(object):
475 def __bool__(self):
476 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000477 for prefix in tuple("<>!=")+('',):
478 false = (), [], [], '', 0
479 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000480
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000481 falseFormat = prefix + '?' * len(false)
482 packedFalse = struct.pack(falseFormat, *false)
483 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000484
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 trueFormat = prefix + '?' * len(true)
486 packedTrue = struct.pack(trueFormat, *true)
487 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000488
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000489 self.assertEqual(len(true), len(unpackedTrue))
490 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000491
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000492 for t in unpackedFalse:
493 self.assertFalse(t)
494 for t in unpackedTrue:
495 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000496
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000497 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000498
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000501 if len(packed) != 1:
502 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
503 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000504
Mark Dickinson94628ee2010-07-12 20:03:24 +0000505 try:
506 struct.pack(prefix + '?', ExplodingBool())
507 except IOError:
508 pass
509 else:
510 self.fail("Expected IOError: struct.pack(%r, "
511 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000512
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000513 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
514 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000515
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000516 def test_count_overflow(self):
517 hugecount = '{}b'.format(sys.maxsize+1)
518 self.assertRaises(struct.error, struct.calcsize, hugecount)
519
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000520 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
521 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000522
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000523 if IS32BIT:
524 def test_crasher(self):
525 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
526
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000527 def test_trailing_counter(self):
528 store = array.array('b', b' '*100)
529
530 # format lists containing only count spec should result in an error
531 self.assertRaises(struct.error, struct.pack, '12345')
532 self.assertRaises(struct.error, struct.unpack, '12345', '')
533 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
534 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
535
536 # Format lists with trailing count spec should result in an error
537 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
538 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
539 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
540 'x')
541 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
542 0)
543
544 # Mixed format tests
545 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
546 self.assertRaises(struct.error, struct.unpack, '14s42',
547 'spam and eggs')
548 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
549 'spam and eggs')
550 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
551
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000552 def test_Struct_reinitialization(self):
553 # Issue 9422: there was a memory leak when reinitializing a
554 # Struct instance. This test can be used to detect the leak
555 # when running with regrtest -L.
556 s = struct.Struct('i')
557 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000558
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000559def test_main():
560 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000561
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000562if __name__ == '__main__':
563 test_main()