blob: c315d8a3152670ed6af9b7b8df2e726fcabfab3c [file] [log] [blame]
Martin Blais2856e5f2006-05-26 12:03:27 +00001import array
Benjamin Petersond5299862008-06-11 01:31:28 +00002import unittest
3import struct
Bob Ippolito2fd39772006-05-29 22:55:48 +00004import warnings
Georg Brandl6269fec2009-01-01 12:15:31 +00005warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
6 DeprecationWarning)
Barry Warsaw07a0eec1996-12-12 23:34:06 +00007
Benjamin Petersond5299862008-06-11 01:31:28 +00008from functools import wraps
Georg Brandla4f46e12010-02-07 17:03:15 +00009from test.test_support import run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +000010
Tim Peters17e17d42001-06-13 22:45:27 +000011import sys
12ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000013IS32BIT = sys.maxsize == 0x7fffffff
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000014
15integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
16
17# Native 'q' packing isn't available on systems that don't have the C
18# long long type.
19try:
20 struct.pack('q', 5)
21except struct.error:
22 HAVE_LONG_LONG = False
23else:
24 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000025
26def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000027 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000028
29def bigendian_to_native(value):
30 if ISBIGENDIAN:
31 return value
32 else:
33 return string_reverse(value)
34
Benjamin Petersond5299862008-06-11 01:31:28 +000035class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000036
Benjamin Petersond5299862008-06-11 01:31:28 +000037 def check_float_coerce(self, format, number):
38 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
Mark Dickinson1c0c78c2010-03-05 14:36:20 +000039 with warnings.catch_warnings():
40 warnings.filterwarnings(
41 "ignore",
42 category=DeprecationWarning,
43 message=".*integer argument expected, got float",
44 module=__name__)
45 self.assertEqual(struct.pack(format, number), struct.pack(format, int(number)))
46
47 with warnings.catch_warnings():
48 warnings.filterwarnings(
49 "error",
50 category=DeprecationWarning,
51 message=".*integer argument expected, got float",
52 module="unittest")
53 self.assertRaises(DeprecationWarning, struct.pack, format, number)
Tim Peters7a3bfc32001-06-12 01:22:22 +000054
Benjamin Petersond5299862008-06-11 01:31:28 +000055 def test_isbigendian(self):
56 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Benjamin Petersond5299862008-06-11 01:31:28 +000058 def test_consistence(self):
59 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000060
Benjamin Petersond5299862008-06-11 01:31:28 +000061 sz = struct.calcsize('i')
62 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000063
Benjamin Petersond5299862008-06-11 01:31:28 +000064 fmt = 'cbxxxxxxhhhhiillffd?'
65 fmt3 = '3c3b18x12h6i6l6f3d3?'
66 sz = struct.calcsize(fmt)
67 sz3 = struct.calcsize(fmt3)
68 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000069
Benjamin Petersond5299862008-06-11 01:31:28 +000070 self.assertRaises(struct.error, struct.pack, 'iii', 3)
71 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
72 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
73 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
74 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
75 s = struct.pack('ii', 1, 2)
76 self.assertRaises(struct.error, struct.unpack, 'iii', s)
77 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000078
Benjamin Petersond5299862008-06-11 01:31:28 +000079 def test_transitiveness(self):
80 c = 'a'
81 b = 1
82 h = 255
83 i = 65535
84 l = 65536
85 f = 3.1415
86 d = 3.1415
87 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000088
Benjamin Petersond5299862008-06-11 01:31:28 +000089 for prefix in ('', '@', '<', '>', '=', '!'):
90 for format in ('xcbhilfd?', 'xcBHILfd?'):
91 format = prefix + format
92 s = struct.pack(format, c, b, h, i, l, f, d, t)
93 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
94 self.assertEqual(cp, c)
95 self.assertEqual(bp, b)
96 self.assertEqual(hp, h)
97 self.assertEqual(ip, i)
98 self.assertEqual(lp, l)
99 self.assertEqual(int(100 * fp), int(100 * f))
100 self.assertEqual(int(100 * dp), int(100 * d))
101 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000102
Benjamin Petersond5299862008-06-11 01:31:28 +0000103 def test_new_features(self):
104 # Test some of the new features in detail
105 # (format, argument, big-endian result, little-endian result, asymmetric)
106 tests = [
107 ('c', 'a', 'a', 'a', 0),
108 ('xc', 'a', '\0a', '\0a', 0),
109 ('cx', 'a', 'a\0', 'a\0', 0),
110 ('s', 'a', 'a', 'a', 0),
111 ('0s', 'helloworld', '', '', 1),
112 ('1s', 'helloworld', 'h', 'h', 1),
113 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
114 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
115 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
116 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
117 ('b', 7, '\7', '\7', 0),
118 ('b', -7, '\371', '\371', 0),
119 ('B', 7, '\7', '\7', 0),
120 ('B', 249, '\371', '\371', 0),
121 ('h', 700, '\002\274', '\274\002', 0),
122 ('h', -700, '\375D', 'D\375', 0),
123 ('H', 700, '\002\274', '\274\002', 0),
124 ('H', 0x10000-700, '\375D', 'D\375', 0),
125 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
126 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
127 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
128 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
129 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
130 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
131 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
132 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
133 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
134 ('d', 2.0, '@\000\000\000\000\000\000\000',
135 '\000\000\000\000\000\000\000@', 0),
136 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
137 ('d', -2.0, '\300\000\000\000\000\000\000\000',
138 '\000\000\000\000\000\000\000\300', 0),
139 ('?', 0, '\0', '\0', 0),
140 ('?', 3, '\1', '\1', 1),
141 ('?', True, '\1', '\1', 0),
142 ('?', [], '\0', '\0', 1),
143 ('?', (1,), '\1', '\1', 1),
144 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000145
Benjamin Petersond5299862008-06-11 01:31:28 +0000146 for fmt, arg, big, lil, asy in tests:
147 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
148 ('='+fmt, ISBIGENDIAN and big or lil)]:
149 res = struct.pack(xfmt, arg)
150 self.assertEqual(res, exp)
151 self.assertEqual(struct.calcsize(xfmt), len(res))
152 rev = struct.unpack(xfmt, res)[0]
153 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000154 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000155
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000156 def test_calcsize(self):
157 expected_size = {
158 'b': 1, 'B': 1,
159 'h': 2, 'H': 2,
160 'i': 4, 'I': 4,
161 'l': 4, 'L': 4,
162 'q': 8, 'Q': 8,
163 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000164
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000165 # standard integer sizes
166 for code in integer_codes:
167 for byteorder in ('=', '<', '>', '!'):
168 format = byteorder+code
169 size = struct.calcsize(format)
170 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000171
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000172 # native integer sizes, except 'q' and 'Q'
173 for format_pair in ('bB', 'hH', 'iI', 'lL'):
174 for byteorder in ['', '@']:
175 signed_size = struct.calcsize(byteorder + format_pair[0])
176 unsigned_size = struct.calcsize(byteorder + format_pair[1])
177 self.assertEqual(signed_size, unsigned_size)
178
179 # bounds for native integer sizes
180 self.assertTrue(struct.calcsize('b')==1)
181 self.assertTrue(2 <= struct.calcsize('h'))
182 self.assertTrue(4 <= struct.calcsize('l'))
183 self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
184 self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
185
186 # tests for native 'q' and 'Q' when applicable
187 if HAVE_LONG_LONG:
188 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
189 self.assertTrue(8 <= struct.calcsize('q'))
190 self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
191
192 def test_integers(self):
193 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000194 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000195
Benjamin Petersond5299862008-06-11 01:31:28 +0000196 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000197 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000198 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000199 self.format = format
200 self.code = format[-1]
201 self.direction = format[:-1]
202 if not self.direction in ('', '@', '=', '<', '>', '!'):
203 raise ValueError("unrecognized packing direction: %s" %
204 self.direction)
205 self.bytesize = struct.calcsize(format)
206 self.bitsize = self.bytesize * 8
207 if self.code in tuple('bhilq'):
208 self.signed = True
209 self.min_value = -(2L**(self.bitsize-1))
210 self.max_value = 2L**(self.bitsize-1) - 1
211 elif self.code in tuple('BHILQ'):
212 self.signed = False
213 self.min_value = 0
214 self.max_value = 2L**self.bitsize - 1
215 else:
216 raise ValueError("unrecognized format code: %s" %
217 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000218
Benjamin Petersond5299862008-06-11 01:31:28 +0000219 def test_one(self, x, pack=struct.pack,
220 unpack=struct.unpack,
221 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000222
223 format = self.format
224 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000225 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000226 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000227 expected += 1L << self.bitsize
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000228 self.assertTrue(expected >= 0)
229 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000230 if len(expected) & 1:
231 expected = "0" + expected
232 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000233 expected = ("\x00" * (self.bytesize - len(expected)) +
234 expected)
235 if (self.direction == '<' or
236 self.direction in ('', '@', '=') and not ISBIGENDIAN):
237 expected = string_reverse(expected)
238 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000239
Benjamin Petersond5299862008-06-11 01:31:28 +0000240 # Pack work?
241 got = pack(format, x)
242 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000243
Benjamin Petersond5299862008-06-11 01:31:28 +0000244 # Unpack work?
245 retrieved = unpack(format, got)[0]
246 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000247
Benjamin Petersond5299862008-06-11 01:31:28 +0000248 # Adding any byte should cause a "too big" error.
249 self.assertRaises((struct.error, TypeError), unpack, format,
250 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000251 else:
252 # x is out of range -- verify pack realizes that.
Mark Dickinson5fd3af22009-07-07 15:08:28 +0000253 self.assertRaises(struct.error, pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000254
255 def run(self):
256 from random import randrange
257
258 # Create all interesting powers of 2.
259 values = []
260 for exp in range(self.bitsize + 3):
261 values.append(1L << exp)
262
263 # Add some random values.
264 for i in range(self.bitsize):
265 val = 0L
266 for j in range(self.bytesize):
267 val = (val << 8) | randrange(256)
268 values.append(val)
269
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000270 # Values absorbed from other tests
271 values.extend([300, 700000, sys.maxint*4])
272
273 # Try all those, and their negations, and +-1 from
274 # them. Note that this tests all power-of-2
275 # boundaries in range, and a few out of range, plus
276 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000277 for base in values:
278 for val in -base, base:
279 for incr in -1, 0, 1:
280 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000281 self.test_one(int(x))
282 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000283
284 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000285 class NotAnIntNS(object):
286 def __int__(self):
287 return 42
288
289 def __long__(self):
290 return 1729L
291
292 class NotAnIntOS:
293 def __int__(self):
294 return 10585
295
296 def __long__(self):
297 return -163L
298
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000299 for badobject in ("a string", 3+42j, randrange,
300 NotAnIntNS(), NotAnIntOS()):
301 self.assertRaises(struct.error,
302 struct.pack, format,
303 badobject)
Benjamin Petersond5299862008-06-11 01:31:28 +0000304
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000305 byteorders = '', '@', '=', '<', '>', '!'
306 for code in integer_codes:
307 for byteorder in byteorders:
308 if (byteorder in ('', '@') and code in ('q', 'Q') and
309 not HAVE_LONG_LONG):
310 continue
311 format = byteorder+code
312 t = IntTester(format)
313 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000314
315 def test_p_code(self):
316 # Test p ("Pascal string") code.
317 for code, input, expected, expectedback in [
318 ('p','abc', '\x00', ''),
319 ('1p', 'abc', '\x00', ''),
320 ('2p', 'abc', '\x01a', 'a'),
321 ('3p', 'abc', '\x02ab', 'ab'),
322 ('4p', 'abc', '\x03abc', 'abc'),
323 ('5p', 'abc', '\x03abc\x00', 'abc'),
324 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
325 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
326 got = struct.pack(code, input)
327 self.assertEqual(got, expected)
328 (got,) = struct.unpack(code, got)
329 self.assertEqual(got, expectedback)
330
331 def test_705836(self):
332 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
333 # from the low-order discarded bits could propagate into the exponent
334 # field, causing the result to be wrong by a factor of 2.
335 import math
336
337 for base in range(1, 33):
338 # smaller <- largest representable float less than base.
339 delta = 0.5
340 while base - delta / 2.0 != base:
341 delta /= 2.0
342 smaller = base - delta
343 # Packing this rounds away a solid string of trailing 1 bits.
344 packed = struct.pack("<f", smaller)
345 unpacked = struct.unpack("<f", packed)[0]
346 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
347 # 16, respectively.
348 self.assertEqual(base, unpacked)
349 bigpacked = struct.pack(">f", smaller)
350 self.assertEqual(bigpacked, string_reverse(packed))
351 unpacked = struct.unpack(">f", bigpacked)[0]
352 self.assertEqual(base, unpacked)
353
354 # Largest finite IEEE single.
355 big = (1 << 24) - 1
356 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000357 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000358 unpacked = struct.unpack(">f", packed)[0]
359 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000360
Benjamin Petersond5299862008-06-11 01:31:28 +0000361 # The same, but tack on a 1 bit so it rounds up to infinity.
362 big = (1 << 25) - 1
363 big = math.ldexp(big, 127 - 24)
364 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000365
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000366 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000367 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
368 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000369 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000370 self.check_float_coerce(endian + fmt, 1.0)
371 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000372
Benjamin Petersond5299862008-06-11 01:31:28 +0000373 def test_unpack_from(self):
374 test_string = 'abcd01234'
375 fmt = '4s'
376 s = struct.Struct(fmt)
377 for cls in (str, buffer):
378 data = cls(test_string)
379 self.assertEqual(s.unpack_from(data), ('abcd',))
380 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
381 self.assertEqual(s.unpack_from(data, 4), ('0123',))
382 for i in xrange(6):
383 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
384 for i in xrange(6, len(test_string) + 1):
385 self.assertRaises(struct.error, s.unpack_from, data, i)
386 for cls in (str, buffer):
387 data = cls(test_string)
388 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
389 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
390 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
391 for i in xrange(6):
392 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
393 for i in xrange(6, len(test_string) + 1):
394 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000395
Benjamin Petersond5299862008-06-11 01:31:28 +0000396 def test_pack_into(self):
397 test_string = 'Reykjavik rocks, eow!'
398 writable_buf = array.array('c', ' '*100)
399 fmt = '21s'
400 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000401
Benjamin Petersond5299862008-06-11 01:31:28 +0000402 # Test without offset
403 s.pack_into(writable_buf, 0, test_string)
404 from_buf = writable_buf.tostring()[:len(test_string)]
405 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000406
Benjamin Petersond5299862008-06-11 01:31:28 +0000407 # Test with offset.
408 s.pack_into(writable_buf, 10, test_string)
409 from_buf = writable_buf.tostring()[:len(test_string)+10]
410 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000411
Benjamin Petersond5299862008-06-11 01:31:28 +0000412 # Go beyond boundaries.
413 small_buf = array.array('c', ' '*10)
414 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
415 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000416
Georg Brandl0638a082009-02-13 11:03:59 +0000417 # Test bogus offset (issue 3694)
418 sb = small_buf
419 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
420
Benjamin Petersond5299862008-06-11 01:31:28 +0000421 def test_pack_into_fn(self):
422 test_string = 'Reykjavik rocks, eow!'
423 writable_buf = array.array('c', ' '*100)
424 fmt = '21s'
425 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000426
Benjamin Petersond5299862008-06-11 01:31:28 +0000427 # Test without offset.
428 pack_into(writable_buf, 0, test_string)
429 from_buf = writable_buf.tostring()[:len(test_string)]
430 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000431
Benjamin Petersond5299862008-06-11 01:31:28 +0000432 # Test with offset.
433 pack_into(writable_buf, 10, test_string)
434 from_buf = writable_buf.tostring()[:len(test_string)+10]
435 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000436
Benjamin Petersond5299862008-06-11 01:31:28 +0000437 # Go beyond boundaries.
438 small_buf = array.array('c', ' '*10)
439 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
440 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000441
Benjamin Petersond5299862008-06-11 01:31:28 +0000442 def test_unpack_with_buffer(self):
443 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
444 data1 = array.array('B', '\x12\x34\x56\x78')
445 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
446 for data in [data1, data2]:
447 value, = struct.unpack('>I', data)
448 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000449
Benjamin Petersond5299862008-06-11 01:31:28 +0000450 def test_bool(self):
451 for prefix in tuple("<>!=")+('',):
452 false = (), [], [], '', 0
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000453 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000454
Benjamin Petersond5299862008-06-11 01:31:28 +0000455 falseFormat = prefix + '?' * len(false)
456 packedFalse = struct.pack(falseFormat, *false)
457 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000458
Benjamin Petersond5299862008-06-11 01:31:28 +0000459 trueFormat = prefix + '?' * len(true)
460 packedTrue = struct.pack(trueFormat, *true)
461 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000462
Benjamin Petersond5299862008-06-11 01:31:28 +0000463 self.assertEqual(len(true), len(unpackedTrue))
464 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000465
Benjamin Petersond5299862008-06-11 01:31:28 +0000466 for t in unpackedFalse:
467 self.assertFalse(t)
468 for t in unpackedTrue:
469 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000470
Benjamin Petersond5299862008-06-11 01:31:28 +0000471 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000472
Benjamin Petersond5299862008-06-11 01:31:28 +0000473 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000474
Benjamin Petersond5299862008-06-11 01:31:28 +0000475 if len(packed) != 1:
476 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
477 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000478
Benjamin Petersond5299862008-06-11 01:31:28 +0000479 for c in '\x01\x7f\xff\x0f\xf0':
480 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000481
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000482 if IS32BIT:
483 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000484 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000485
486
Tim Petersf733abb2007-01-30 03:03:46 +0000487
Benjamin Petersond5299862008-06-11 01:31:28 +0000488def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000489 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000490
Benjamin Petersond5299862008-06-11 01:31:28 +0000491if __name__ == '__main__':
492 test_main()