blob: d3840cc9962c6cdd9271dcce6867a6ec0aa01183 [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 = [
85 ('c', 'a', 'a', 'a', 0),
86 ('xc', 'a', '\0a', '\0a', 0),
87 ('cx', 'a', 'a\0', 'a\0', 0),
88 ('s', 'a', 'a', 'a', 0),
89 ('0s', 'helloworld', '', '', 1),
90 ('1s', 'helloworld', 'h', 'h', 1),
91 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
92 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
93 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
94 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
95 ('b', 7, '\7', '\7', 0),
96 ('b', -7, '\371', '\371', 0),
97 ('B', 7, '\7', '\7', 0),
98 ('B', 249, '\371', '\371', 0),
99 ('h', 700, '\002\274', '\274\002', 0),
100 ('h', -700, '\375D', 'D\375', 0),
101 ('H', 700, '\002\274', '\274\002', 0),
102 ('H', 0x10000-700, '\375D', 'D\375', 0),
103 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
104 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
105 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
106 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
107 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
108 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
109 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
110 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
111 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
112 ('d', 2.0, '@\000\000\000\000\000\000\000',
113 '\000\000\000\000\000\000\000@', 0),
114 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
115 ('d', -2.0, '\300\000\000\000\000\000\000\000',
116 '\000\000\000\000\000\000\000\300', 0),
117 ('?', 0, '\0', '\0', 0),
118 ('?', 3, '\1', '\1', 1),
119 ('?', True, '\1', '\1', 0),
120 ('?', [], '\0', '\0', 1),
121 ('?', (1,), '\1', '\1', 1),
122 ]
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:
125 big = bytes(big, "latin-1")
126 lil = bytes(lil, "latin-1")
127 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
128 ('='+fmt, ISBIGENDIAN and big or lil)]:
129 res = struct.pack(xfmt, arg)
130 self.assertEqual(res, exp)
131 self.assertEqual(struct.calcsize(xfmt), len(res))
132 rev = struct.unpack(xfmt, res)[0]
133 if isinstance(arg, str):
134 # Strings are returned as bytes since you can't know the
135 # encoding of the string when packed.
136 arg = bytes(arg, 'latin1')
137 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000138 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000139
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000140 def test_calcsize(self):
141 expected_size = {
142 'b': 1, 'B': 1,
143 'h': 2, 'H': 2,
144 'i': 4, 'I': 4,
145 'l': 4, 'L': 4,
146 'q': 8, 'Q': 8,
147 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000148
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000149 # standard integer sizes
150 for code in integer_codes:
151 for byteorder in '=', '<', '>', '!':
152 format = byteorder+code
153 size = struct.calcsize(format)
154 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000155
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000156 # native integer sizes
157 native_pairs = 'bB', 'hH', 'iI', 'lL'
158 if HAVE_LONG_LONG:
159 native_pairs += 'qQ',
160 for format_pair in native_pairs:
161 for byteorder in '', '@':
162 signed_size = struct.calcsize(byteorder + format_pair[0])
163 unsigned_size = struct.calcsize(byteorder + format_pair[1])
164 self.assertEqual(signed_size, unsigned_size)
165
166 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000167 self.assertEqual(struct.calcsize('b'), 1)
168 self.assertLessEqual(2, struct.calcsize('h'))
169 self.assertLessEqual(4, struct.calcsize('l'))
170 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
171 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000172 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000173 self.assertLessEqual(8, struct.calcsize('q'))
174 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000175
176 def test_integers(self):
177 # Integer tests (bBhHiIlLqQ).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000178 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000179
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000180 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000181 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000182 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000183 self.format = format
184 self.code = format[-1]
185 self.byteorder = format[:-1]
186 if not self.byteorder in byteorders:
187 raise ValueError("unrecognized packing byteorder: %s" %
188 self.byteorder)
189 self.bytesize = struct.calcsize(format)
190 self.bitsize = self.bytesize * 8
191 if self.code in tuple('bhilq'):
192 self.signed = True
193 self.min_value = -(2**(self.bitsize-1))
194 self.max_value = 2**(self.bitsize-1) - 1
195 elif self.code in tuple('BHILQ'):
196 self.signed = False
197 self.min_value = 0
198 self.max_value = 2**self.bitsize - 1
199 else:
200 raise ValueError("unrecognized format code: %s" %
201 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000202
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000203 def test_one(self, x, pack=struct.pack,
204 unpack=struct.unpack,
205 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000206
207 format = self.format
208 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000209 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000210 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000211 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000212 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000213 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000214 if len(expected) & 1:
215 expected = "0" + expected
216 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000217 expected = (b"\x00" * (self.bytesize - len(expected)) +
218 expected)
219 if (self.byteorder == '<' or
220 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
221 expected = string_reverse(expected)
222 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 # Pack work?
225 got = pack(format, x)
226 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 # Unpack work?
229 retrieved = unpack(format, got)[0]
230 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000231
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000232 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000233 self.assertRaises((struct.error, TypeError), unpack, format,
234 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000235 else:
236 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000237 self.assertRaises((OverflowError, ValueError, struct.error),
238 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000239
240 def run(self):
241 from random import randrange
242
243 # Create all interesting powers of 2.
244 values = []
245 for exp in range(self.bitsize + 3):
246 values.append(1 << exp)
247
248 # Add some random values.
249 for i in range(self.bitsize):
250 val = 0
251 for j in range(self.bytesize):
252 val = (val << 8) | randrange(256)
253 values.append(val)
254
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000255 # Values absorbed from other tests
256 values.extend([300, 700000, sys.maxsize*4])
257
258 # Try all those, and their negations, and +-1 from
259 # them. Note that this tests all power-of-2
260 # boundaries in range, and a few out of range, plus
261 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000262 for base in values:
263 for val in -base, base:
264 for incr in -1, 0, 1:
265 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000266 self.test_one(x)
267
268 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000269 class NotAnInt:
270 def __int__(self):
271 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000272
Mark Dickinsone9493a12010-04-04 08:52:51 +0000273 # Objects with an '__index__' method should be allowed
274 # to pack as integers. That is assuming the implemented
275 # '__index__' method returns and 'int' or 'long'.
276 class Indexable(object):
277 def __init__(self, value):
278 self._value = value
279
280 def __index__(self):
281 return self._value
282
283 # If the '__index__' method raises a type error, then
284 # '__int__' should be used with a deprecation warning.
285 class BadIndex(object):
286 def __index__(self):
287 raise TypeError
288
289 def __int__(self):
290 return 42
291
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000292 self.assertRaises((TypeError, struct.error),
293 struct.pack, self.format,
294 "a string")
295 self.assertRaises((TypeError, struct.error),
296 struct.pack, self.format,
297 randrange)
298 self.assertRaises((TypeError, struct.error),
299 struct.pack, self.format,
300 3+42j)
301 self.assertRaises((TypeError, struct.error),
302 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000303 NotAnInt())
304 self.assertRaises((TypeError, struct.error),
305 struct.pack, self.format,
306 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000307
Mark Dickinsone9493a12010-04-04 08:52:51 +0000308 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000309 for obj in (Indexable(0), Indexable(10), Indexable(17),
310 Indexable(42), Indexable(100), Indexable(127)):
311 try:
312 struct.pack(format, obj)
313 except:
314 self.fail("integer code pack failed on object "
315 "with '__index__' method")
316
Mark Dickinsone9493a12010-04-04 08:52:51 +0000317 # Check for bogus values from '__index__'.
318 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
319 Indexable({'a': 1}), Indexable([1, 2, 3])):
320 self.assertRaises((TypeError, struct.error),
321 struct.pack, self.format,
322 obj)
323
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000324 for code in integer_codes:
325 for byteorder in byteorders:
326 if (byteorder in ('', '@') and code in ('q', 'Q') and
327 not HAVE_LONG_LONG):
328 continue
329 format = byteorder+code
330 t = IntTester(format)
331 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000332
333 def test_p_code(self):
334 # Test p ("Pascal string") code.
335 for code, input, expected, expectedback in [
336 ('p','abc', '\x00', b''),
337 ('1p', 'abc', '\x00', b''),
338 ('2p', 'abc', '\x01a', b'a'),
339 ('3p', 'abc', '\x02ab', b'ab'),
340 ('4p', 'abc', '\x03abc', b'abc'),
341 ('5p', 'abc', '\x03abc\x00', b'abc'),
342 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
343 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
344 expected = bytes(expected, "latin-1")
345 got = struct.pack(code, input)
346 self.assertEqual(got, expected)
347 (got,) = struct.unpack(code, got)
348 self.assertEqual(got, expectedback)
349
350 def test_705836(self):
351 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
352 # from the low-order discarded bits could propagate into the exponent
353 # field, causing the result to be wrong by a factor of 2.
354 import math
355
356 for base in range(1, 33):
357 # smaller <- largest representable float less than base.
358 delta = 0.5
359 while base - delta / 2.0 != base:
360 delta /= 2.0
361 smaller = base - delta
362 # Packing this rounds away a solid string of trailing 1 bits.
363 packed = struct.pack("<f", smaller)
364 unpacked = struct.unpack("<f", packed)[0]
365 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
366 # 16, respectively.
367 self.assertEqual(base, unpacked)
368 bigpacked = struct.pack(">f", smaller)
369 self.assertEqual(bigpacked, string_reverse(packed))
370 unpacked = struct.unpack(">f", bigpacked)[0]
371 self.assertEqual(base, unpacked)
372
373 # Largest finite IEEE single.
374 big = (1 << 24) - 1
375 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000376 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000377 unpacked = struct.unpack(">f", packed)[0]
378 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000379
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000380 # The same, but tack on a 1 bit so it rounds up to infinity.
381 big = (1 << 25) - 1
382 big = math.ldexp(big, 127 - 24)
383 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000384
Mark Dickinsonea835e72009-04-19 20:40:33 +0000385 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000386 for byteorder in '', '@', '=', '<', '>', '!':
387 for code in integer_codes:
388 if (byteorder in ('', '@') and code in ('q', 'Q') and
389 not HAVE_LONG_LONG):
390 continue
391 format = byteorder + code
392 self.assertRaises(struct.error, struct.pack, format, 1.0)
393 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000394 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
395 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
396
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000397 def test_unpack_from(self):
398 test_string = b'abcd01234'
399 fmt = '4s'
400 s = struct.Struct(fmt)
401 for cls in (bytes, bytearray):
402 data = cls(test_string)
403 if not isinstance(data, (bytes, bytearray)):
404 bytes_data = bytes(data, 'latin1')
405 else:
406 bytes_data = data
407 self.assertEqual(s.unpack_from(data), (b'abcd',))
408 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
409 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
410 for i in range(6):
411 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
412 for i in range(6, len(test_string) + 1):
413 self.assertRaises(struct.error, s.unpack_from, data, i)
414 for cls in (bytes, bytearray):
415 data = cls(test_string)
416 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
417 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
418 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
419 for i in range(6):
420 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
421 for i in range(6, len(test_string) + 1):
422 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000423
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000424 def test_pack_into(self):
425 test_string = b'Reykjavik rocks, eow!'
426 writable_buf = array.array('b', b' '*100)
427 fmt = '21s'
428 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000429
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000430 # Test without offset
431 s.pack_into(writable_buf, 0, test_string)
432 from_buf = writable_buf.tostring()[:len(test_string)]
433 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000434
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000435 # Test with offset.
436 s.pack_into(writable_buf, 10, test_string)
437 from_buf = writable_buf.tostring()[:len(test_string)+10]
438 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000439
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000440 # Go beyond boundaries.
441 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000442 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
443 test_string)
444 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
445 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000446
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000447 # Test bogus offset (issue 3694)
448 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000449 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
450 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000451
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000452 def test_pack_into_fn(self):
453 test_string = b'Reykjavik rocks, eow!'
454 writable_buf = array.array('b', b' '*100)
455 fmt = '21s'
456 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000457
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000458 # Test without offset.
459 pack_into(writable_buf, 0, test_string)
460 from_buf = writable_buf.tostring()[:len(test_string)]
461 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000463 # Test with offset.
464 pack_into(writable_buf, 10, test_string)
465 from_buf = writable_buf.tostring()[:len(test_string)+10]
466 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000467
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000468 # Go beyond boundaries.
469 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000470 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
471 test_string)
472 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
473 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000474
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000475 def test_unpack_with_buffer(self):
476 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
477 data1 = array.array('B', b'\x12\x34\x56\x78')
478 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
479 for data in [data1, data2]:
480 value, = struct.unpack('>I', data)
481 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000482
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000483 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000484 class ExplodingBool(object):
485 def __bool__(self):
486 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000487 for prefix in tuple("<>!=")+('',):
488 false = (), [], [], '', 0
489 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000490
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000491 falseFormat = prefix + '?' * len(false)
492 packedFalse = struct.pack(falseFormat, *false)
493 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000494
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000495 trueFormat = prefix + '?' * len(true)
496 packedTrue = struct.pack(trueFormat, *true)
497 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000498
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 self.assertEqual(len(true), len(unpackedTrue))
500 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 for t in unpackedFalse:
503 self.assertFalse(t)
504 for t in unpackedTrue:
505 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000508
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000509 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000510
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000511 if len(packed) != 1:
512 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
513 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000514
Benjamin Petersonde73c452010-07-07 18:54:59 +0000515 self.assertRaises(IOError, struct.pack, prefix + '?',
516 ExplodingBool())
517
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000518 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
519 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000520
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000521 def test_count_overflow(self):
522 hugecount = '{}b'.format(sys.maxsize+1)
523 self.assertRaises(struct.error, struct.calcsize, hugecount)
524
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000525 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
526 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000527
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000528 if IS32BIT:
529 def test_crasher(self):
530 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
531
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000532 def test_trailing_counter(self):
533 store = array.array('b', b' '*100)
534
535 # format lists containing only count spec should result in an error
536 self.assertRaises(struct.error, struct.pack, '12345')
537 self.assertRaises(struct.error, struct.unpack, '12345', '')
538 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
539 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
540
541 # Format lists with trailing count spec should result in an error
542 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
543 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
544 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
545 'x')
546 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
547 0)
548
549 # Mixed format tests
550 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
551 self.assertRaises(struct.error, struct.unpack, '14s42',
552 'spam and eggs')
553 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
554 'spam and eggs')
555 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
556
557
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()