blob: 39ccb27017aaf454d85255d68937ec4076669baa [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
167 self.assertTrue(struct.calcsize('b')==1)
168 self.assertTrue(2 <= struct.calcsize('h'))
169 self.assertTrue(4 <= struct.calcsize('l'))
170 self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
171 self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
172 if HAVE_LONG_LONG:
173 self.assertTrue(8 <= struct.calcsize('q'))
174 self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
175
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
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000212 self.assertTrue(expected >= 0)
213 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 Dickinsonb9f751a2010-04-03 15:07:40 +0000272 self.assertRaises((TypeError, struct.error),
273 struct.pack, self.format,
274 "a string")
275 self.assertRaises((TypeError, struct.error),
276 struct.pack, self.format,
277 randrange)
278 self.assertRaises((TypeError, struct.error),
279 struct.pack, self.format,
280 3+42j)
281 self.assertRaises((TypeError, struct.error),
282 struct.pack, self.format,
283 NotAnInt)
284
285 for code in integer_codes:
286 for byteorder in byteorders:
287 if (byteorder in ('', '@') and code in ('q', 'Q') and
288 not HAVE_LONG_LONG):
289 continue
290 format = byteorder+code
291 t = IntTester(format)
292 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000293
294 def test_p_code(self):
295 # Test p ("Pascal string") code.
296 for code, input, expected, expectedback in [
297 ('p','abc', '\x00', b''),
298 ('1p', 'abc', '\x00', b''),
299 ('2p', 'abc', '\x01a', b'a'),
300 ('3p', 'abc', '\x02ab', b'ab'),
301 ('4p', 'abc', '\x03abc', b'abc'),
302 ('5p', 'abc', '\x03abc\x00', b'abc'),
303 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
304 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
305 expected = bytes(expected, "latin-1")
306 got = struct.pack(code, input)
307 self.assertEqual(got, expected)
308 (got,) = struct.unpack(code, got)
309 self.assertEqual(got, expectedback)
310
311 def test_705836(self):
312 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
313 # from the low-order discarded bits could propagate into the exponent
314 # field, causing the result to be wrong by a factor of 2.
315 import math
316
317 for base in range(1, 33):
318 # smaller <- largest representable float less than base.
319 delta = 0.5
320 while base - delta / 2.0 != base:
321 delta /= 2.0
322 smaller = base - delta
323 # Packing this rounds away a solid string of trailing 1 bits.
324 packed = struct.pack("<f", smaller)
325 unpacked = struct.unpack("<f", packed)[0]
326 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
327 # 16, respectively.
328 self.assertEqual(base, unpacked)
329 bigpacked = struct.pack(">f", smaller)
330 self.assertEqual(bigpacked, string_reverse(packed))
331 unpacked = struct.unpack(">f", bigpacked)[0]
332 self.assertEqual(base, unpacked)
333
334 # Largest finite IEEE single.
335 big = (1 << 24) - 1
336 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000337 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000338 unpacked = struct.unpack(">f", packed)[0]
339 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000340
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000341 # The same, but tack on a 1 bit so it rounds up to infinity.
342 big = (1 << 25) - 1
343 big = math.ldexp(big, 127 - 24)
344 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000345
Mark Dickinsonea835e72009-04-19 20:40:33 +0000346 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000347 for byteorder in '', '@', '=', '<', '>', '!':
348 for code in integer_codes:
349 if (byteorder in ('', '@') and code in ('q', 'Q') and
350 not HAVE_LONG_LONG):
351 continue
352 format = byteorder + code
353 self.assertRaises(struct.error, struct.pack, format, 1.0)
354 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000355 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
356 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
357
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000358 def test_unpack_from(self):
359 test_string = b'abcd01234'
360 fmt = '4s'
361 s = struct.Struct(fmt)
362 for cls in (bytes, bytearray):
363 data = cls(test_string)
364 if not isinstance(data, (bytes, bytearray)):
365 bytes_data = bytes(data, 'latin1')
366 else:
367 bytes_data = data
368 self.assertEqual(s.unpack_from(data), (b'abcd',))
369 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
370 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
371 for i in range(6):
372 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
373 for i in range(6, len(test_string) + 1):
374 self.assertRaises(struct.error, s.unpack_from, data, i)
375 for cls in (bytes, bytearray):
376 data = cls(test_string)
377 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
378 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
379 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
380 for i in range(6):
381 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
382 for i in range(6, len(test_string) + 1):
383 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000384
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000385 def test_pack_into(self):
386 test_string = b'Reykjavik rocks, eow!'
387 writable_buf = array.array('b', b' '*100)
388 fmt = '21s'
389 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000390
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000391 # Test without offset
392 s.pack_into(writable_buf, 0, test_string)
393 from_buf = writable_buf.tostring()[:len(test_string)]
394 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000395
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000396 # Test with offset.
397 s.pack_into(writable_buf, 10, test_string)
398 from_buf = writable_buf.tostring()[:len(test_string)+10]
399 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000400
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000401 # Go beyond boundaries.
402 small_buf = array.array('b', b' '*10)
403 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
404 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000405
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000406 # Test bogus offset (issue 3694)
407 sb = small_buf
408 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
409
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000410 def test_pack_into_fn(self):
411 test_string = b'Reykjavik rocks, eow!'
412 writable_buf = array.array('b', b' '*100)
413 fmt = '21s'
414 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000415
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000416 # Test without offset.
417 pack_into(writable_buf, 0, test_string)
418 from_buf = writable_buf.tostring()[:len(test_string)]
419 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000420
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000421 # Test with offset.
422 pack_into(writable_buf, 10, test_string)
423 from_buf = writable_buf.tostring()[:len(test_string)+10]
424 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000425
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000426 # Go beyond boundaries.
427 small_buf = array.array('b', b' '*10)
428 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
429 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000430
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000431 def test_unpack_with_buffer(self):
432 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
433 data1 = array.array('B', b'\x12\x34\x56\x78')
434 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
435 for data in [data1, data2]:
436 value, = struct.unpack('>I', data)
437 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000438
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000439 def test_bool(self):
440 for prefix in tuple("<>!=")+('',):
441 false = (), [], [], '', 0
442 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000443
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000444 falseFormat = prefix + '?' * len(false)
445 packedFalse = struct.pack(falseFormat, *false)
446 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 trueFormat = prefix + '?' * len(true)
449 packedTrue = struct.pack(trueFormat, *true)
450 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000451
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000452 self.assertEqual(len(true), len(unpackedTrue))
453 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000454
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000455 for t in unpackedFalse:
456 self.assertFalse(t)
457 for t in unpackedTrue:
458 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000459
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000460 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000461
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000462 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 if len(packed) != 1:
465 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
466 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000467
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000468 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
469 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000470
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000471 if IS32BIT:
472 def test_crasher(self):
473 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
474
475
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000476def test_main():
477 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000478
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000479if __name__ == '__main__':
480 test_main()