blob: ecf38ba28b06f5a9fbc469f588d74adce30d3fea [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)
50 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
51 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
52 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.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000237 self.assertRaises(struct.error, pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000238
239 def run(self):
240 from random import randrange
241
242 # Create all interesting powers of 2.
243 values = []
244 for exp in range(self.bitsize + 3):
245 values.append(1 << exp)
246
247 # Add some random values.
248 for i in range(self.bitsize):
249 val = 0
250 for j in range(self.bytesize):
251 val = (val << 8) | randrange(256)
252 values.append(val)
253
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000254 # Values absorbed from other tests
255 values.extend([300, 700000, sys.maxsize*4])
256
257 # Try all those, and their negations, and +-1 from
258 # them. Note that this tests all power-of-2
259 # boundaries in range, and a few out of range, plus
260 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000261 for base in values:
262 for val in -base, base:
263 for incr in -1, 0, 1:
264 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000265 self.test_one(x)
266
267 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000268 class NotAnInt:
269 def __int__(self):
270 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000271
Mark Dickinsone9493a12010-04-04 08:52:51 +0000272 # Objects with an '__index__' method should be allowed
273 # to pack as integers. That is assuming the implemented
274 # '__index__' method returns and 'int' or 'long'.
275 class Indexable(object):
276 def __init__(self, value):
277 self._value = value
278
279 def __index__(self):
280 return self._value
281
282 # If the '__index__' method raises a type error, then
283 # '__int__' should be used with a deprecation warning.
284 class BadIndex(object):
285 def __index__(self):
286 raise TypeError
287
288 def __int__(self):
289 return 42
290
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000291 self.assertRaises((TypeError, struct.error),
292 struct.pack, self.format,
293 "a string")
294 self.assertRaises((TypeError, struct.error),
295 struct.pack, self.format,
296 randrange)
297 self.assertRaises((TypeError, struct.error),
298 struct.pack, self.format,
299 3+42j)
300 self.assertRaises((TypeError, struct.error),
301 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000302 NotAnInt())
303 self.assertRaises((TypeError, struct.error),
304 struct.pack, self.format,
305 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000306
Mark Dickinsone9493a12010-04-04 08:52:51 +0000307 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000308 for obj in (Indexable(0), Indexable(10), Indexable(17),
309 Indexable(42), Indexable(100), Indexable(127)):
310 try:
311 struct.pack(format, obj)
312 except:
313 self.fail("integer code pack failed on object "
314 "with '__index__' method")
315
Mark Dickinsone9493a12010-04-04 08:52:51 +0000316 # Check for bogus values from '__index__'.
317 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
318 Indexable({'a': 1}), Indexable([1, 2, 3])):
319 self.assertRaises((TypeError, struct.error),
320 struct.pack, self.format,
321 obj)
322
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000323 for code in integer_codes:
324 for byteorder in byteorders:
325 if (byteorder in ('', '@') and code in ('q', 'Q') and
326 not HAVE_LONG_LONG):
327 continue
328 format = byteorder+code
329 t = IntTester(format)
330 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000331
332 def test_p_code(self):
333 # Test p ("Pascal string") code.
334 for code, input, expected, expectedback in [
335 ('p','abc', '\x00', b''),
336 ('1p', 'abc', '\x00', b''),
337 ('2p', 'abc', '\x01a', b'a'),
338 ('3p', 'abc', '\x02ab', b'ab'),
339 ('4p', 'abc', '\x03abc', b'abc'),
340 ('5p', 'abc', '\x03abc\x00', b'abc'),
341 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
342 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
343 expected = bytes(expected, "latin-1")
344 got = struct.pack(code, input)
345 self.assertEqual(got, expected)
346 (got,) = struct.unpack(code, got)
347 self.assertEqual(got, expectedback)
348
349 def test_705836(self):
350 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
351 # from the low-order discarded bits could propagate into the exponent
352 # field, causing the result to be wrong by a factor of 2.
353 import math
354
355 for base in range(1, 33):
356 # smaller <- largest representable float less than base.
357 delta = 0.5
358 while base - delta / 2.0 != base:
359 delta /= 2.0
360 smaller = base - delta
361 # Packing this rounds away a solid string of trailing 1 bits.
362 packed = struct.pack("<f", smaller)
363 unpacked = struct.unpack("<f", packed)[0]
364 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
365 # 16, respectively.
366 self.assertEqual(base, unpacked)
367 bigpacked = struct.pack(">f", smaller)
368 self.assertEqual(bigpacked, string_reverse(packed))
369 unpacked = struct.unpack(">f", bigpacked)[0]
370 self.assertEqual(base, unpacked)
371
372 # Largest finite IEEE single.
373 big = (1 << 24) - 1
374 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000375 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000376 unpacked = struct.unpack(">f", packed)[0]
377 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000378
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000379 # The same, but tack on a 1 bit so it rounds up to infinity.
380 big = (1 << 25) - 1
381 big = math.ldexp(big, 127 - 24)
382 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000383
Mark Dickinsonea835e72009-04-19 20:40:33 +0000384 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000385 for byteorder in '', '@', '=', '<', '>', '!':
386 for code in integer_codes:
387 if (byteorder in ('', '@') and code in ('q', 'Q') and
388 not HAVE_LONG_LONG):
389 continue
390 format = byteorder + code
391 self.assertRaises(struct.error, struct.pack, format, 1.0)
392 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000393 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
394 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
395
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000396 def test_unpack_from(self):
397 test_string = b'abcd01234'
398 fmt = '4s'
399 s = struct.Struct(fmt)
400 for cls in (bytes, bytearray):
401 data = cls(test_string)
402 if not isinstance(data, (bytes, bytearray)):
403 bytes_data = bytes(data, 'latin1')
404 else:
405 bytes_data = data
406 self.assertEqual(s.unpack_from(data), (b'abcd',))
407 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
408 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
409 for i in range(6):
410 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
411 for i in range(6, len(test_string) + 1):
412 self.assertRaises(struct.error, s.unpack_from, data, i)
413 for cls in (bytes, bytearray):
414 data = cls(test_string)
415 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
416 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
417 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
418 for i in range(6):
419 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
420 for i in range(6, len(test_string) + 1):
421 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000422
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000423 def test_pack_into(self):
424 test_string = b'Reykjavik rocks, eow!'
425 writable_buf = array.array('b', b' '*100)
426 fmt = '21s'
427 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000428
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000429 # Test without offset
430 s.pack_into(writable_buf, 0, test_string)
431 from_buf = writable_buf.tostring()[:len(test_string)]
432 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000433
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000434 # Test with offset.
435 s.pack_into(writable_buf, 10, test_string)
436 from_buf = writable_buf.tostring()[:len(test_string)+10]
437 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000438
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000439 # Go beyond boundaries.
440 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000441 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
442 test_string)
443 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
444 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000445
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000446 # Test bogus offset (issue 3694)
447 sb = small_buf
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000448 self.assertRaises(TypeError, struct.pack_into, b'', sb, None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000449
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000450 def test_pack_into_fn(self):
451 test_string = b'Reykjavik rocks, eow!'
452 writable_buf = array.array('b', b' '*100)
453 fmt = '21s'
454 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000455
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000456 # Test without offset.
457 pack_into(writable_buf, 0, test_string)
458 from_buf = writable_buf.tostring()[:len(test_string)]
459 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 # Test with offset.
462 pack_into(writable_buf, 10, test_string)
463 from_buf = writable_buf.tostring()[:len(test_string)+10]
464 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 # Go beyond boundaries.
467 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000468 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
469 test_string)
470 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
471 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000472
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000473 def test_unpack_with_buffer(self):
474 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
475 data1 = array.array('B', b'\x12\x34\x56\x78')
476 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
477 for data in [data1, data2]:
478 value, = struct.unpack('>I', data)
479 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000480
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000481 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000482 class ExplodingBool(object):
483 def __bool__(self):
484 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 for prefix in tuple("<>!=")+('',):
486 false = (), [], [], '', 0
487 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000488
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000489 falseFormat = prefix + '?' * len(false)
490 packedFalse = struct.pack(falseFormat, *false)
491 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000492
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000493 trueFormat = prefix + '?' * len(true)
494 packedTrue = struct.pack(trueFormat, *true)
495 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000496
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000497 self.assertEqual(len(true), len(unpackedTrue))
498 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000500 for t in unpackedFalse:
501 self.assertFalse(t)
502 for t in unpackedTrue:
503 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000508
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000509 if len(packed) != 1:
510 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
511 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000512
Benjamin Petersonde73c452010-07-07 18:54:59 +0000513 self.assertRaises(IOError, struct.pack, prefix + '?',
514 ExplodingBool())
515
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000516 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
517 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000518
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000519 def test_count_overflow(self):
520 hugecount = '{}b'.format(sys.maxsize+1)
521 self.assertRaises(struct.error, struct.calcsize, hugecount)
522
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000523 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
524 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000525
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000526 if IS32BIT:
527 def test_crasher(self):
528 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
529
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000530 def test_trailing_counter(self):
531 store = array.array('b', b' '*100)
532
533 # format lists containing only count spec should result in an error
534 self.assertRaises(struct.error, struct.pack, '12345')
535 self.assertRaises(struct.error, struct.unpack, '12345', '')
536 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
537 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
538
539 # Format lists with trailing count spec should result in an error
540 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
541 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
542 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
543 'x')
544 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
545 0)
546
547 # Mixed format tests
548 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
549 self.assertRaises(struct.error, struct.unpack, '14s42',
550 'spam and eggs')
551 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
552 'spam and eggs')
553 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
554
555
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000556
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000557def test_main():
558 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000559
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000560if __name__ == '__main__':
561 test_main()