blob: 6ca35ca31cf972f96b9727fbf29ae5ecd3dc879f [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
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000216 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000217 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000218 expected = (b"\x00" * (self.bytesize - len(expected)) +
219 expected)
220 if (self.byteorder == '<' or
221 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
222 expected = string_reverse(expected)
223 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000224
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000225 # Pack work?
226 got = pack(format, x)
227 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000228
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000229 # Unpack work?
230 retrieved = unpack(format, got)[0]
231 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000232
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000233 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000234 self.assertRaises((struct.error, TypeError), unpack, format,
235 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000236 else:
237 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000238 self.assertRaises((OverflowError, ValueError, struct.error),
239 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000240
241 def run(self):
242 from random import randrange
243
244 # Create all interesting powers of 2.
245 values = []
246 for exp in range(self.bitsize + 3):
247 values.append(1 << exp)
248
249 # Add some random values.
250 for i in range(self.bitsize):
251 val = 0
252 for j in range(self.bytesize):
253 val = (val << 8) | randrange(256)
254 values.append(val)
255
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000256 # Values absorbed from other tests
257 values.extend([300, 700000, sys.maxsize*4])
258
259 # Try all those, and their negations, and +-1 from
260 # them. Note that this tests all power-of-2
261 # boundaries in range, and a few out of range, plus
262 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000263 for base in values:
264 for val in -base, base:
265 for incr in -1, 0, 1:
266 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000267 self.test_one(x)
268
269 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000270 class NotAnInt:
271 def __int__(self):
272 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000273
Mark Dickinsone9493a12010-04-04 08:52:51 +0000274 # Objects with an '__index__' method should be allowed
275 # to pack as integers. That is assuming the implemented
276 # '__index__' method returns and 'int' or 'long'.
277 class Indexable(object):
278 def __init__(self, value):
279 self._value = value
280
281 def __index__(self):
282 return self._value
283
284 # If the '__index__' method raises a type error, then
285 # '__int__' should be used with a deprecation warning.
286 class BadIndex(object):
287 def __index__(self):
288 raise TypeError
289
290 def __int__(self):
291 return 42
292
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000293 self.assertRaises((TypeError, struct.error),
294 struct.pack, self.format,
295 "a string")
296 self.assertRaises((TypeError, struct.error),
297 struct.pack, self.format,
298 randrange)
299 self.assertRaises((TypeError, struct.error),
300 struct.pack, self.format,
301 3+42j)
302 self.assertRaises((TypeError, struct.error),
303 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000304 NotAnInt())
305 self.assertRaises((TypeError, struct.error),
306 struct.pack, self.format,
307 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000308
Mark Dickinsone9493a12010-04-04 08:52:51 +0000309 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000310 for obj in (Indexable(0), Indexable(10), Indexable(17),
311 Indexable(42), Indexable(100), Indexable(127)):
312 try:
313 struct.pack(format, obj)
314 except:
315 self.fail("integer code pack failed on object "
316 "with '__index__' method")
317
Mark Dickinsone9493a12010-04-04 08:52:51 +0000318 # Check for bogus values from '__index__'.
319 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
320 Indexable({'a': 1}), Indexable([1, 2, 3])):
321 self.assertRaises((TypeError, struct.error),
322 struct.pack, self.format,
323 obj)
324
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000325 for code in integer_codes:
326 for byteorder in byteorders:
327 if (byteorder in ('', '@') and code in ('q', 'Q') and
328 not HAVE_LONG_LONG):
329 continue
330 format = byteorder+code
331 t = IntTester(format)
332 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000333
334 def test_p_code(self):
335 # Test p ("Pascal string") code.
336 for code, input, expected, expectedback in [
337 ('p','abc', '\x00', b''),
338 ('1p', 'abc', '\x00', b''),
339 ('2p', 'abc', '\x01a', b'a'),
340 ('3p', 'abc', '\x02ab', b'ab'),
341 ('4p', 'abc', '\x03abc', b'abc'),
342 ('5p', 'abc', '\x03abc\x00', b'abc'),
343 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
344 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
345 expected = bytes(expected, "latin-1")
346 got = struct.pack(code, input)
347 self.assertEqual(got, expected)
348 (got,) = struct.unpack(code, got)
349 self.assertEqual(got, expectedback)
350
351 def test_705836(self):
352 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
353 # from the low-order discarded bits could propagate into the exponent
354 # field, causing the result to be wrong by a factor of 2.
355 import math
356
357 for base in range(1, 33):
358 # smaller <- largest representable float less than base.
359 delta = 0.5
360 while base - delta / 2.0 != base:
361 delta /= 2.0
362 smaller = base - delta
363 # Packing this rounds away a solid string of trailing 1 bits.
364 packed = struct.pack("<f", smaller)
365 unpacked = struct.unpack("<f", packed)[0]
366 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
367 # 16, respectively.
368 self.assertEqual(base, unpacked)
369 bigpacked = struct.pack(">f", smaller)
370 self.assertEqual(bigpacked, string_reverse(packed))
371 unpacked = struct.unpack(">f", bigpacked)[0]
372 self.assertEqual(base, unpacked)
373
374 # Largest finite IEEE single.
375 big = (1 << 24) - 1
376 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000377 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000378 unpacked = struct.unpack(">f", packed)[0]
379 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000380
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000381 # The same, but tack on a 1 bit so it rounds up to infinity.
382 big = (1 << 25) - 1
383 big = math.ldexp(big, 127 - 24)
384 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000385
Mark Dickinsonea835e72009-04-19 20:40:33 +0000386 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000387 for byteorder in '', '@', '=', '<', '>', '!':
388 for code in integer_codes:
389 if (byteorder in ('', '@') and code in ('q', 'Q') and
390 not HAVE_LONG_LONG):
391 continue
392 format = byteorder + code
393 self.assertRaises(struct.error, struct.pack, format, 1.0)
394 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000395 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
396 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
397
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000398 def test_unpack_from(self):
399 test_string = b'abcd01234'
400 fmt = '4s'
401 s = struct.Struct(fmt)
402 for cls in (bytes, bytearray):
403 data = cls(test_string)
404 if not isinstance(data, (bytes, bytearray)):
405 bytes_data = bytes(data, 'latin1')
406 else:
407 bytes_data = data
408 self.assertEqual(s.unpack_from(data), (b'abcd',))
409 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
410 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
411 for i in range(6):
412 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
413 for i in range(6, len(test_string) + 1):
414 self.assertRaises(struct.error, s.unpack_from, data, i)
415 for cls in (bytes, bytearray):
416 data = cls(test_string)
417 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
418 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
419 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
420 for i in range(6):
421 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
422 for i in range(6, len(test_string) + 1):
423 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000424
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000425 def test_pack_into(self):
426 test_string = b'Reykjavik rocks, eow!'
427 writable_buf = array.array('b', b' '*100)
428 fmt = '21s'
429 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000430
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000431 # Test without offset
432 s.pack_into(writable_buf, 0, test_string)
433 from_buf = writable_buf.tostring()[:len(test_string)]
434 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000435
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000436 # Test with offset.
437 s.pack_into(writable_buf, 10, test_string)
438 from_buf = writable_buf.tostring()[:len(test_string)+10]
439 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000440
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000441 # Go beyond boundaries.
442 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000443 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
444 test_string)
445 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
446 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000447
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000448 # Test bogus offset (issue 3694)
449 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000450 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
451 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000452
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000453 def test_pack_into_fn(self):
454 test_string = b'Reykjavik rocks, eow!'
455 writable_buf = array.array('b', b' '*100)
456 fmt = '21s'
457 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000458
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000459 # Test without offset.
460 pack_into(writable_buf, 0, test_string)
461 from_buf = writable_buf.tostring()[:len(test_string)]
462 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 # Test with offset.
465 pack_into(writable_buf, 10, test_string)
466 from_buf = writable_buf.tostring()[:len(test_string)+10]
467 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000468
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000469 # Go beyond boundaries.
470 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000471 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
472 test_string)
473 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
474 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000475
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000476 def test_unpack_with_buffer(self):
477 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
478 data1 = array.array('B', b'\x12\x34\x56\x78')
479 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
480 for data in [data1, data2]:
481 value, = struct.unpack('>I', data)
482 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000483
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000484 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000485 class ExplodingBool(object):
486 def __bool__(self):
487 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000488 for prefix in tuple("<>!=")+('',):
489 false = (), [], [], '', 0
490 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000491
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000492 falseFormat = prefix + '?' * len(false)
493 packedFalse = struct.pack(falseFormat, *false)
494 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000495
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000496 trueFormat = prefix + '?' * len(true)
497 packedTrue = struct.pack(trueFormat, *true)
498 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000499
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000500 self.assertEqual(len(true), len(unpackedTrue))
501 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000502
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000503 for t in unpackedFalse:
504 self.assertFalse(t)
505 for t in unpackedTrue:
506 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000507
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000508 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000509
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000510 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 if len(packed) != 1:
513 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
514 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000515
Mark Dickinson94628ee2010-07-12 20:03:24 +0000516 try:
517 struct.pack(prefix + '?', ExplodingBool())
518 except IOError:
519 pass
520 else:
521 self.fail("Expected IOError: struct.pack(%r, "
522 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000523
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000524 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
525 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000526
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000527 def test_count_overflow(self):
528 hugecount = '{}b'.format(sys.maxsize+1)
529 self.assertRaises(struct.error, struct.calcsize, hugecount)
530
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000531 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
532 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000533
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000534 if IS32BIT:
535 def test_crasher(self):
536 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
537
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000538 def test_trailing_counter(self):
539 store = array.array('b', b' '*100)
540
541 # format lists containing only count spec should result in an error
542 self.assertRaises(struct.error, struct.pack, '12345')
543 self.assertRaises(struct.error, struct.unpack, '12345', '')
544 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
545 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
546
547 # Format lists with trailing count spec should result in an error
548 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
549 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
550 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
551 'x')
552 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
553 0)
554
555 # Mixed format tests
556 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
557 self.assertRaises(struct.error, struct.unpack, '14s42',
558 'spam and eggs')
559 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
560 'spam and eggs')
561 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
562
563
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000564
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000565def test_main():
566 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000567
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000568if __name__ == '__main__':
569 test_main()