blob: dc75858c8a11022a41d3ad4c23a65af4ad1de92f [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
Antoine Pitrou45d9c912011-10-06 15:27:40 +020011integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000012byteorders = '', '@', '=', '<', '>', '!'
13
Antoine Pitrou45d9c912011-10-06 15:27:40 +020014def iter_integer_formats(byteorders=byteorders):
15 for code in integer_codes:
16 for byteorder in byteorders:
17 if (byteorder in ('', '@') and code in ('q', 'Q') and
18 not HAVE_LONG_LONG):
19 continue
20 if (byteorder not in ('', '@') and code in ('n', 'N')):
21 continue
22 yield code, byteorder
23
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000024# Native 'q' packing isn't available on systems that don't have the C
25# long long type.
26try:
27 struct.pack('q', 5)
28except struct.error:
29 HAVE_LONG_LONG = False
30else:
31 HAVE_LONG_LONG = True
32
Tim Peters17e17d42001-06-13 22:45:27 +000033def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000034 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000035
36def bigendian_to_native(value):
37 if ISBIGENDIAN:
38 return value
39 else:
40 return string_reverse(value)
41
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000042class StructTest(unittest.TestCase):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000044 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000045
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000046 def test_consistence(self):
47 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000048
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000049 sz = struct.calcsize('i')
50 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000051
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000052 fmt = 'cbxxxxxxhhhhiillffd?'
53 fmt3 = '3c3b18x12h6i6l6f3d3?'
54 sz = struct.calcsize(fmt)
55 sz3 = struct.calcsize(fmt3)
56 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000058 self.assertRaises(struct.error, struct.pack, 'iii', 3)
59 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000060 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
61 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000062 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
63 s = struct.pack('ii', 1, 2)
64 self.assertRaises(struct.error, struct.unpack, 'iii', s)
65 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000066
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000067 def test_transitiveness(self):
68 c = b'a'
69 b = 1
70 h = 255
71 i = 65535
72 l = 65536
73 f = 3.1415
74 d = 3.1415
75 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000076
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000077 for prefix in ('', '@', '<', '>', '=', '!'):
78 for format in ('xcbhilfd?', 'xcBHILfd?'):
79 format = prefix + format
80 s = struct.pack(format, c, b, h, i, l, f, d, t)
81 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
82 self.assertEqual(cp, c)
83 self.assertEqual(bp, b)
84 self.assertEqual(hp, h)
85 self.assertEqual(ip, i)
86 self.assertEqual(lp, l)
87 self.assertEqual(int(100 * fp), int(100 * f))
88 self.assertEqual(int(100 * dp), int(100 * d))
89 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000090
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000091 def test_new_features(self):
92 # Test some of the new features in detail
93 # (format, argument, big-endian result, little-endian result, asymmetric)
94 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +000095 ('c', b'a', b'a', b'a', 0),
96 ('xc', b'a', b'\0a', b'\0a', 0),
97 ('cx', b'a', b'a\0', b'a\0', 0),
98 ('s', b'a', b'a', b'a', 0),
99 ('0s', b'helloworld', b'', b'', 1),
100 ('1s', b'helloworld', b'h', b'h', 1),
101 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
102 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
103 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
104 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
105 ('b', 7, b'\7', b'\7', 0),
106 ('b', -7, b'\371', b'\371', 0),
107 ('B', 7, b'\7', b'\7', 0),
108 ('B', 249, b'\371', b'\371', 0),
109 ('h', 700, b'\002\274', b'\274\002', 0),
110 ('h', -700, b'\375D', b'D\375', 0),
111 ('H', 700, b'\002\274', b'\274\002', 0),
112 ('H', 0x10000-700, b'\375D', b'D\375', 0),
113 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
114 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
115 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
116 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
117 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
118 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
119 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
120 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
121 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
122 ('d', 2.0, b'@\000\000\000\000\000\000\000',
123 b'\000\000\000\000\000\000\000@', 0),
124 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
125 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
126 b'\000\000\000\000\000\000\000\300', 0),
127 ('?', 0, b'\0', b'\0', 0),
128 ('?', 3, b'\1', b'\1', 1),
129 ('?', True, b'\1', b'\1', 0),
130 ('?', [], b'\0', b'\0', 1),
131 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000132 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000133
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000134 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000135 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
136 ('='+fmt, ISBIGENDIAN and big or lil)]:
137 res = struct.pack(xfmt, arg)
138 self.assertEqual(res, exp)
139 self.assertEqual(struct.calcsize(xfmt), len(res))
140 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000141 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000142 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000143
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000144 def test_calcsize(self):
145 expected_size = {
146 'b': 1, 'B': 1,
147 'h': 2, 'H': 2,
148 'i': 4, 'I': 4,
149 'l': 4, 'L': 4,
150 'q': 8, 'Q': 8,
151 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000152
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000153 # standard integer sizes
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200154 for code, byteorder in iter_integer_formats(('=', '<', '>', '!')):
155 format = byteorder+code
156 size = struct.calcsize(format)
157 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000158
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000159 # native integer sizes
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200160 native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000161 if HAVE_LONG_LONG:
162 native_pairs += 'qQ',
163 for format_pair in native_pairs:
164 for byteorder in '', '@':
165 signed_size = struct.calcsize(byteorder + format_pair[0])
166 unsigned_size = struct.calcsize(byteorder + format_pair[1])
167 self.assertEqual(signed_size, unsigned_size)
168
169 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000170 self.assertEqual(struct.calcsize('b'), 1)
171 self.assertLessEqual(2, struct.calcsize('h'))
172 self.assertLessEqual(4, struct.calcsize('l'))
173 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
174 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000175 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000176 self.assertLessEqual(8, struct.calcsize('q'))
177 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200178 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i'))
179 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000180
181 def test_integers(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200182 # Integer tests (bBhHiIlLqQnN).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000183 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000184
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000185 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000186 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000187 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000188 self.format = format
189 self.code = format[-1]
190 self.byteorder = format[:-1]
191 if not self.byteorder in byteorders:
192 raise ValueError("unrecognized packing byteorder: %s" %
193 self.byteorder)
194 self.bytesize = struct.calcsize(format)
195 self.bitsize = self.bytesize * 8
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200196 if self.code in tuple('bhilqn'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000197 self.signed = True
198 self.min_value = -(2**(self.bitsize-1))
199 self.max_value = 2**(self.bitsize-1) - 1
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200200 elif self.code in tuple('BHILQN'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000201 self.signed = False
202 self.min_value = 0
203 self.max_value = 2**self.bitsize - 1
204 else:
205 raise ValueError("unrecognized format code: %s" %
206 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000207
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000208 def test_one(self, x, pack=struct.pack,
209 unpack=struct.unpack,
210 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000211
212 format = self.format
213 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000214 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000215 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000216 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000217 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000218 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000219 if len(expected) & 1:
220 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000221 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000222 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000223 expected = (b"\x00" * (self.bytesize - len(expected)) +
224 expected)
225 if (self.byteorder == '<' or
226 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
227 expected = string_reverse(expected)
228 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000229
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000230 # Pack work?
231 got = pack(format, x)
232 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000233
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000234 # Unpack work?
235 retrieved = unpack(format, got)[0]
236 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000237
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000238 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000239 self.assertRaises((struct.error, TypeError), unpack, format,
240 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000241 else:
242 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000243 self.assertRaises((OverflowError, ValueError, struct.error),
244 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000245
246 def run(self):
247 from random import randrange
248
249 # Create all interesting powers of 2.
250 values = []
251 for exp in range(self.bitsize + 3):
252 values.append(1 << exp)
253
254 # Add some random values.
255 for i in range(self.bitsize):
256 val = 0
257 for j in range(self.bytesize):
258 val = (val << 8) | randrange(256)
259 values.append(val)
260
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000261 # Values absorbed from other tests
262 values.extend([300, 700000, sys.maxsize*4])
263
264 # Try all those, and their negations, and +-1 from
265 # them. Note that this tests all power-of-2
266 # boundaries in range, and a few out of range, plus
267 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000268 for base in values:
269 for val in -base, base:
270 for incr in -1, 0, 1:
271 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000272 self.test_one(x)
273
274 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000275 class NotAnInt:
276 def __int__(self):
277 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000278
Mark Dickinsone9493a12010-04-04 08:52:51 +0000279 # Objects with an '__index__' method should be allowed
280 # to pack as integers. That is assuming the implemented
281 # '__index__' method returns and 'int' or 'long'.
282 class Indexable(object):
283 def __init__(self, value):
284 self._value = value
285
286 def __index__(self):
287 return self._value
288
289 # If the '__index__' method raises a type error, then
290 # '__int__' should be used with a deprecation warning.
291 class BadIndex(object):
292 def __index__(self):
293 raise TypeError
294
295 def __int__(self):
296 return 42
297
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000298 self.assertRaises((TypeError, struct.error),
299 struct.pack, self.format,
300 "a string")
301 self.assertRaises((TypeError, struct.error),
302 struct.pack, self.format,
303 randrange)
304 self.assertRaises((TypeError, struct.error),
305 struct.pack, self.format,
306 3+42j)
307 self.assertRaises((TypeError, struct.error),
308 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000309 NotAnInt())
310 self.assertRaises((TypeError, struct.error),
311 struct.pack, self.format,
312 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000313
Mark Dickinsone9493a12010-04-04 08:52:51 +0000314 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000315 for obj in (Indexable(0), Indexable(10), Indexable(17),
316 Indexable(42), Indexable(100), Indexable(127)):
317 try:
318 struct.pack(format, obj)
319 except:
320 self.fail("integer code pack failed on object "
321 "with '__index__' method")
322
Mark Dickinsone9493a12010-04-04 08:52:51 +0000323 # Check for bogus values from '__index__'.
324 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
325 Indexable({'a': 1}), Indexable([1, 2, 3])):
326 self.assertRaises((TypeError, struct.error),
327 struct.pack, self.format,
328 obj)
329
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200330 for code, byteorder in iter_integer_formats():
331 format = byteorder+code
332 t = IntTester(format)
333 t.run()
334
335 def test_nN_code(self):
336 # n and N don't exist in standard sizes
337 def assertStructError(func, *args, **kwargs):
338 with self.assertRaises(struct.error) as cm:
339 func(*args, **kwargs)
340 self.assertIn("bad char in struct format", str(cm.exception))
341 for code in 'nN':
342 for byteorder in ('=', '<', '>', '!'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000343 format = byteorder+code
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200344 assertStructError(struct.calcsize, format)
345 assertStructError(struct.pack, format, 0)
346 assertStructError(struct.unpack, format, b"")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000347
348 def test_p_code(self):
349 # Test p ("Pascal string") code.
350 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000351 ('p', b'abc', b'\x00', b''),
352 ('1p', b'abc', b'\x00', b''),
353 ('2p', b'abc', b'\x01a', b'a'),
354 ('3p', b'abc', b'\x02ab', b'ab'),
355 ('4p', b'abc', b'\x03abc', b'abc'),
356 ('5p', b'abc', b'\x03abc\x00', b'abc'),
357 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
358 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000359 got = struct.pack(code, input)
360 self.assertEqual(got, expected)
361 (got,) = struct.unpack(code, got)
362 self.assertEqual(got, expectedback)
363
364 def test_705836(self):
365 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
366 # from the low-order discarded bits could propagate into the exponent
367 # field, causing the result to be wrong by a factor of 2.
368 import math
369
370 for base in range(1, 33):
371 # smaller <- largest representable float less than base.
372 delta = 0.5
373 while base - delta / 2.0 != base:
374 delta /= 2.0
375 smaller = base - delta
376 # Packing this rounds away a solid string of trailing 1 bits.
377 packed = struct.pack("<f", smaller)
378 unpacked = struct.unpack("<f", packed)[0]
379 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
380 # 16, respectively.
381 self.assertEqual(base, unpacked)
382 bigpacked = struct.pack(">f", smaller)
383 self.assertEqual(bigpacked, string_reverse(packed))
384 unpacked = struct.unpack(">f", bigpacked)[0]
385 self.assertEqual(base, unpacked)
386
387 # Largest finite IEEE single.
388 big = (1 << 24) - 1
389 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000390 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000391 unpacked = struct.unpack(">f", packed)[0]
392 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000393
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000394 # The same, but tack on a 1 bit so it rounds up to infinity.
395 big = (1 << 25) - 1
396 big = math.ldexp(big, 127 - 24)
397 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000398
Mark Dickinsonea835e72009-04-19 20:40:33 +0000399 def test_1530559(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200400 for code, byteorder in iter_integer_formats():
401 format = byteorder + code
402 self.assertRaises(struct.error, struct.pack, format, 1.0)
403 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000404 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
405 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
406
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000407 def test_unpack_from(self):
408 test_string = b'abcd01234'
409 fmt = '4s'
410 s = struct.Struct(fmt)
411 for cls in (bytes, bytearray):
412 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000413 self.assertEqual(s.unpack_from(data), (b'abcd',))
414 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
415 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
416 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000417 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000418 for i in range(6, len(test_string) + 1):
419 self.assertRaises(struct.error, s.unpack_from, data, i)
420 for cls in (bytes, bytearray):
421 data = cls(test_string)
422 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
423 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
424 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
425 for i in range(6):
426 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
427 for i in range(6, len(test_string) + 1):
428 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000429
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000430 def test_pack_into(self):
431 test_string = b'Reykjavik rocks, eow!'
432 writable_buf = array.array('b', b' '*100)
433 fmt = '21s'
434 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000435
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000436 # Test without offset
437 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000438 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000439 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000440
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000441 # Test with offset.
442 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000443 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000444 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000445
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000446 # Go beyond boundaries.
447 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000448 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
449 test_string)
450 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
451 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000452
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000453 # Test bogus offset (issue 3694)
454 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000455 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
456 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000457
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000458 def test_pack_into_fn(self):
459 test_string = b'Reykjavik rocks, eow!'
460 writable_buf = array.array('b', b' '*100)
461 fmt = '21s'
462 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 # Test without offset.
465 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000466 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000467 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000468
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000469 # Test with offset.
470 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000471 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000472 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000473
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000474 # Go beyond boundaries.
475 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000476 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
477 test_string)
478 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
479 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000480
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000481 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200482 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000483 data1 = array.array('B', b'\x12\x34\x56\x78')
484 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
485 for data in [data1, data2]:
486 value, = struct.unpack('>I', data)
487 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000488
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000489 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000490 class ExplodingBool(object):
491 def __bool__(self):
492 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000493 for prefix in tuple("<>!=")+('',):
494 false = (), [], [], '', 0
495 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000496
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000497 falseFormat = prefix + '?' * len(false)
498 packedFalse = struct.pack(falseFormat, *false)
499 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000500
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000501 trueFormat = prefix + '?' * len(true)
502 packedTrue = struct.pack(trueFormat, *true)
503 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 self.assertEqual(len(true), len(unpackedTrue))
506 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000507
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000508 for t in unpackedFalse:
509 self.assertFalse(t)
510 for t in unpackedTrue:
511 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000512
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000513 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000514
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000515 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000516
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000517 if len(packed) != 1:
518 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
519 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000520
Mark Dickinson94628ee2010-07-12 20:03:24 +0000521 try:
522 struct.pack(prefix + '?', ExplodingBool())
523 except IOError:
524 pass
525 else:
526 self.fail("Expected IOError: struct.pack(%r, "
527 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000528
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000529 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
530 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000531
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000532 def test_count_overflow(self):
533 hugecount = '{}b'.format(sys.maxsize+1)
534 self.assertRaises(struct.error, struct.calcsize, hugecount)
535
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000536 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
537 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000538
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000539 if IS32BIT:
540 def test_crasher(self):
541 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
542
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000543 def test_trailing_counter(self):
544 store = array.array('b', b' '*100)
545
546 # format lists containing only count spec should result in an error
547 self.assertRaises(struct.error, struct.pack, '12345')
548 self.assertRaises(struct.error, struct.unpack, '12345', '')
549 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
550 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
551
552 # Format lists with trailing count spec should result in an error
553 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
554 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x')
555 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
556 'x')
557 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
558 0)
559
560 # Mixed format tests
561 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
562 self.assertRaises(struct.error, struct.unpack, '14s42',
563 'spam and eggs')
564 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
565 'spam and eggs')
566 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
567
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000568 def test_Struct_reinitialization(self):
569 # Issue 9422: there was a memory leak when reinitializing a
570 # Struct instance. This test can be used to detect the leak
571 # when running with regrtest -L.
572 s = struct.Struct('i')
573 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000574
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000575def test_main():
576 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000577
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000578if __name__ == '__main__':
579 test_main()