blob: 16c2b9e2ce294bc8c55f3f628897f62e5e8be0bf [file] [log] [blame]
Florent Xiclunadb4a3212010-03-20 22:21:02 +00001import os
Martin Blais2856e5f2006-05-26 12:03:27 +00002import array
Benjamin Petersond5299862008-06-11 01:31:28 +00003import unittest
4import struct
Florent Xiclunadb4a3212010-03-20 22:21:02 +00005import inspect
6from test.test_support import run_unittest, check_warnings, check_py3k_warnings
Benjamin Petersond5299862008-06-11 01:31:28 +00007
Tim Peters17e17d42001-06-13 22:45:27 +00008import sys
9ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000010IS32BIT = sys.maxsize == 0x7fffffff
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000011
12integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
13
Florent Xiclunadb4a3212010-03-20 22:21:02 +000014testmod_filename = os.path.splitext(__file__)[0] + '.py'
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000015# Native 'q' packing isn't available on systems that don't have the C
16# long long type.
17try:
18 struct.pack('q', 5)
19except struct.error:
20 HAVE_LONG_LONG = False
21else:
22 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000023
24def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000025 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000026
27def bigendian_to_native(value):
28 if ISBIGENDIAN:
29 return value
30 else:
31 return string_reverse(value)
32
Benjamin Petersond5299862008-06-11 01:31:28 +000033class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000034
Benjamin Petersond5299862008-06-11 01:31:28 +000035 def check_float_coerce(self, format, number):
Mark Dickinson154b7ad2010-03-07 16:24:45 +000036 # SF bug 1530559. struct.pack raises TypeError where it used
37 # to convert.
Florent Xiclunadb4a3212010-03-20 22:21:02 +000038 with check_warnings((".*integer argument expected, got float",
39 DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +000040 got = struct.pack(format, number)
Florent Xiclunadb4a3212010-03-20 22:21:02 +000041 lineno = inspect.currentframe().f_lineno - 1
42 self.assertEqual(w.filename, testmod_filename)
43 self.assertEqual(w.lineno, lineno)
44 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +000045 expected = struct.pack(format, int(number))
46 self.assertEqual(got, expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +000047
Benjamin Petersond5299862008-06-11 01:31:28 +000048 def test_isbigendian(self):
49 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000050
Benjamin Petersond5299862008-06-11 01:31:28 +000051 def test_consistence(self):
52 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000053
Benjamin Petersond5299862008-06-11 01:31:28 +000054 sz = struct.calcsize('i')
55 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000056
Benjamin Petersond5299862008-06-11 01:31:28 +000057 fmt = 'cbxxxxxxhhhhiillffd?'
58 fmt3 = '3c3b18x12h6i6l6f3d3?'
59 sz = struct.calcsize(fmt)
60 sz3 = struct.calcsize(fmt3)
61 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000062
Benjamin Petersond5299862008-06-11 01:31:28 +000063 self.assertRaises(struct.error, struct.pack, 'iii', 3)
64 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Peterson0b00b6b2010-07-09 13:33:03 +000065 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
66 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Benjamin Petersond5299862008-06-11 01:31:28 +000067 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
68 s = struct.pack('ii', 1, 2)
69 self.assertRaises(struct.error, struct.unpack, 'iii', s)
70 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000071
Benjamin Petersond5299862008-06-11 01:31:28 +000072 def test_transitiveness(self):
73 c = 'a'
74 b = 1
75 h = 255
76 i = 65535
77 l = 65536
78 f = 3.1415
79 d = 3.1415
80 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000081
Benjamin Petersond5299862008-06-11 01:31:28 +000082 for prefix in ('', '@', '<', '>', '=', '!'):
83 for format in ('xcbhilfd?', 'xcBHILfd?'):
84 format = prefix + format
85 s = struct.pack(format, c, b, h, i, l, f, d, t)
86 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
87 self.assertEqual(cp, c)
88 self.assertEqual(bp, b)
89 self.assertEqual(hp, h)
90 self.assertEqual(ip, i)
91 self.assertEqual(lp, l)
92 self.assertEqual(int(100 * fp), int(100 * f))
93 self.assertEqual(int(100 * dp), int(100 * d))
94 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000095
Benjamin Petersond5299862008-06-11 01:31:28 +000096 def test_new_features(self):
97 # Test some of the new features in detail
98 # (format, argument, big-endian result, little-endian result, asymmetric)
99 tests = [
100 ('c', 'a', 'a', 'a', 0),
101 ('xc', 'a', '\0a', '\0a', 0),
102 ('cx', 'a', 'a\0', 'a\0', 0),
103 ('s', 'a', 'a', 'a', 0),
104 ('0s', 'helloworld', '', '', 1),
105 ('1s', 'helloworld', 'h', 'h', 1),
106 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
107 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
108 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
109 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
110 ('b', 7, '\7', '\7', 0),
111 ('b', -7, '\371', '\371', 0),
112 ('B', 7, '\7', '\7', 0),
113 ('B', 249, '\371', '\371', 0),
114 ('h', 700, '\002\274', '\274\002', 0),
115 ('h', -700, '\375D', 'D\375', 0),
116 ('H', 700, '\002\274', '\274\002', 0),
117 ('H', 0x10000-700, '\375D', 'D\375', 0),
118 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
119 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
120 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
121 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
122 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
123 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
124 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
125 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
126 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
127 ('d', 2.0, '@\000\000\000\000\000\000\000',
128 '\000\000\000\000\000\000\000@', 0),
129 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
130 ('d', -2.0, '\300\000\000\000\000\000\000\000',
131 '\000\000\000\000\000\000\000\300', 0),
132 ('?', 0, '\0', '\0', 0),
133 ('?', 3, '\1', '\1', 1),
134 ('?', True, '\1', '\1', 0),
135 ('?', [], '\0', '\0', 1),
136 ('?', (1,), '\1', '\1', 1),
137 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000138
Benjamin Petersond5299862008-06-11 01:31:28 +0000139 for fmt, arg, big, lil, asy in tests:
140 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
141 ('='+fmt, ISBIGENDIAN and big or lil)]:
142 res = struct.pack(xfmt, arg)
143 self.assertEqual(res, exp)
144 self.assertEqual(struct.calcsize(xfmt), len(res))
145 rev = struct.unpack(xfmt, res)[0]
146 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000147 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000148
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000149 def test_calcsize(self):
150 expected_size = {
151 'b': 1, 'B': 1,
152 'h': 2, 'H': 2,
153 'i': 4, 'I': 4,
154 'l': 4, 'L': 4,
155 'q': 8, 'Q': 8,
156 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000157
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000158 # standard integer sizes
159 for code in integer_codes:
160 for byteorder in ('=', '<', '>', '!'):
161 format = byteorder+code
162 size = struct.calcsize(format)
163 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000164
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000165 # native integer sizes, except 'q' and 'Q'
166 for format_pair in ('bB', 'hH', 'iI', 'lL'):
167 for byteorder in ['', '@']:
168 signed_size = struct.calcsize(byteorder + format_pair[0])
169 unsigned_size = struct.calcsize(byteorder + format_pair[1])
170 self.assertEqual(signed_size, unsigned_size)
171
172 # bounds for native integer sizes
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000173 self.assertEqual(struct.calcsize('b'), 1)
174 self.assertLessEqual(2, struct.calcsize('h'))
175 self.assertLessEqual(4, struct.calcsize('l'))
176 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
177 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000178
179 # tests for native 'q' and 'Q' when applicable
180 if HAVE_LONG_LONG:
181 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000182 self.assertLessEqual(8, struct.calcsize('q'))
183 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000184
185 def test_integers(self):
186 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000187 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000188
Benjamin Petersond5299862008-06-11 01:31:28 +0000189 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000190 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000191 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000192 self.format = format
193 self.code = format[-1]
194 self.direction = format[:-1]
195 if not self.direction in ('', '@', '=', '<', '>', '!'):
196 raise ValueError("unrecognized packing direction: %s" %
197 self.direction)
198 self.bytesize = struct.calcsize(format)
199 self.bitsize = self.bytesize * 8
200 if self.code in tuple('bhilq'):
201 self.signed = True
202 self.min_value = -(2L**(self.bitsize-1))
203 self.max_value = 2L**(self.bitsize-1) - 1
204 elif self.code in tuple('BHILQ'):
205 self.signed = False
206 self.min_value = 0
207 self.max_value = 2L**self.bitsize - 1
208 else:
209 raise ValueError("unrecognized format code: %s" %
210 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000211
Benjamin Petersond5299862008-06-11 01:31:28 +0000212 def test_one(self, x, pack=struct.pack,
213 unpack=struct.unpack,
214 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000215
216 format = self.format
217 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000218 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000219 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000220 expected += 1L << self.bitsize
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000221 self.assertGreaterEqual(expected, 0)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000222 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000223 if len(expected) & 1:
224 expected = "0" + expected
225 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000226 expected = ("\x00" * (self.bytesize - len(expected)) +
227 expected)
228 if (self.direction == '<' or
229 self.direction in ('', '@', '=') and not ISBIGENDIAN):
230 expected = string_reverse(expected)
231 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000232
Benjamin Petersond5299862008-06-11 01:31:28 +0000233 # Pack work?
234 got = pack(format, x)
235 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000236
Benjamin Petersond5299862008-06-11 01:31:28 +0000237 # Unpack work?
238 retrieved = unpack(format, got)[0]
239 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000240
Benjamin Petersond5299862008-06-11 01:31:28 +0000241 # Adding any byte should cause a "too big" error.
242 self.assertRaises((struct.error, TypeError), unpack, format,
243 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000244 else:
245 # x is out of range -- verify pack realizes that.
Benjamin Peterson306d88f2010-07-09 13:21:35 +0000246 self.assertRaises((OverflowError, struct.error), pack,
247 format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000248
249 def run(self):
250 from random import randrange
251
252 # Create all interesting powers of 2.
253 values = []
254 for exp in range(self.bitsize + 3):
255 values.append(1L << exp)
256
257 # Add some random values.
258 for i in range(self.bitsize):
259 val = 0L
260 for j in range(self.bytesize):
261 val = (val << 8) | randrange(256)
262 values.append(val)
263
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000264 # Values absorbed from other tests
265 values.extend([300, 700000, sys.maxint*4])
266
267 # Try all those, and their negations, and +-1 from
268 # them. Note that this tests all power-of-2
269 # boundaries in range, and a few out of range, plus
270 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000271 for base in values:
272 for val in -base, base:
273 for incr in -1, 0, 1:
274 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000275 self.test_one(int(x))
276 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000277
278 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000279 class NotAnIntNS(object):
280 def __int__(self):
281 return 42
282
283 def __long__(self):
284 return 1729L
285
286 class NotAnIntOS:
287 def __int__(self):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000288 return 85
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000289
290 def __long__(self):
291 return -163L
292
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000293 # Objects with an '__index__' method should be allowed
294 # to pack as integers. That is assuming the implemented
295 # '__index__' method returns and 'int' or 'long'.
296 class Indexable(object):
297 def __init__(self, value):
298 self._value = value
299
300 def __index__(self):
301 return self._value
302
303 # If the '__index__' method raises a type error, then
304 # '__int__' should be used with a deprecation warning.
305 class BadIndex(object):
306 def __index__(self):
307 raise TypeError
308
309 def __int__(self):
310 return 42
311
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000312 self.assertRaises((TypeError, struct.error),
313 struct.pack, self.format,
314 "a string")
315 self.assertRaises((TypeError, struct.error),
316 struct.pack, self.format,
317 randrange)
318 with check_warnings(("integer argument expected, "
319 "got non-integer", DeprecationWarning)):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000320 self.assertRaises((TypeError, struct.error),
321 struct.pack, self.format,
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000322 3+42j)
Benjamin Petersond5299862008-06-11 01:31:28 +0000323
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000324 # an attempt to convert a non-integer (with an
325 # implicit conversion via __int__) should succeed,
326 # with a DeprecationWarning
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000327 for nonint in NotAnIntNS(), NotAnIntOS(), BadIndex():
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000328 with check_warnings((".*integer argument expected, got non"
329 "-integer", DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000330 got = struct.pack(self.format, nonint)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000331 lineno = inspect.currentframe().f_lineno - 1
332 self.assertEqual(w.filename, testmod_filename)
333 self.assertEqual(w.lineno, lineno)
334 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000335 expected = struct.pack(self.format, int(nonint))
336 self.assertEqual(got, expected)
337
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000338 # Check for legitimate values from '__index__'.
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000339 for obj in (Indexable(0), Indexable(10), Indexable(17),
340 Indexable(42), Indexable(100), Indexable(127)):
341 try:
342 struct.pack(format, obj)
343 except:
344 self.fail("integer code pack failed on object "
345 "with '__index__' method")
346
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000347 # Check for bogus values from '__index__'.
348 for obj in (Indexable('a'), Indexable(u'b'), Indexable(None),
349 Indexable({'a': 1}), Indexable([1, 2, 3])):
350 self.assertRaises((TypeError, struct.error),
351 struct.pack, self.format,
352 obj)
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000353
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000354 byteorders = '', '@', '=', '<', '>', '!'
355 for code in integer_codes:
356 for byteorder in byteorders:
357 if (byteorder in ('', '@') and code in ('q', 'Q') and
358 not HAVE_LONG_LONG):
359 continue
360 format = byteorder+code
361 t = IntTester(format)
362 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000363
364 def test_p_code(self):
365 # Test p ("Pascal string") code.
366 for code, input, expected, expectedback in [
367 ('p','abc', '\x00', ''),
368 ('1p', 'abc', '\x00', ''),
369 ('2p', 'abc', '\x01a', 'a'),
370 ('3p', 'abc', '\x02ab', 'ab'),
371 ('4p', 'abc', '\x03abc', 'abc'),
372 ('5p', 'abc', '\x03abc\x00', 'abc'),
373 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
374 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
375 got = struct.pack(code, input)
376 self.assertEqual(got, expected)
377 (got,) = struct.unpack(code, got)
378 self.assertEqual(got, expectedback)
379
380 def test_705836(self):
381 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
382 # from the low-order discarded bits could propagate into the exponent
383 # field, causing the result to be wrong by a factor of 2.
384 import math
385
386 for base in range(1, 33):
387 # smaller <- largest representable float less than base.
388 delta = 0.5
389 while base - delta / 2.0 != base:
390 delta /= 2.0
391 smaller = base - delta
392 # Packing this rounds away a solid string of trailing 1 bits.
393 packed = struct.pack("<f", smaller)
394 unpacked = struct.unpack("<f", packed)[0]
395 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
396 # 16, respectively.
397 self.assertEqual(base, unpacked)
398 bigpacked = struct.pack(">f", smaller)
399 self.assertEqual(bigpacked, string_reverse(packed))
400 unpacked = struct.unpack(">f", bigpacked)[0]
401 self.assertEqual(base, unpacked)
402
403 # Largest finite IEEE single.
404 big = (1 << 24) - 1
405 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000406 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000407 unpacked = struct.unpack(">f", packed)[0]
408 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000409
Benjamin Petersond5299862008-06-11 01:31:28 +0000410 # The same, but tack on a 1 bit so it rounds up to infinity.
411 big = (1 << 25) - 1
412 big = math.ldexp(big, 127 - 24)
413 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000414
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000415 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000416 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
417 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000418 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000419 self.check_float_coerce(endian + fmt, 1.0)
420 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000421
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000422 def test_unpack_from(self, cls=str):
423 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000424 fmt = '4s'
425 s = struct.Struct(fmt)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000426
427 self.assertEqual(s.unpack_from(data), ('abcd',))
428 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
429 for i in xrange(6):
430 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
431 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
432 for i in xrange(6, len(data) + 1):
433 self.assertRaises(struct.error, s.unpack_from, data, i)
434 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000435
Benjamin Petersond5299862008-06-11 01:31:28 +0000436 def test_pack_into(self):
437 test_string = 'Reykjavik rocks, eow!'
438 writable_buf = array.array('c', ' '*100)
439 fmt = '21s'
440 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000441
Benjamin Petersond5299862008-06-11 01:31:28 +0000442 # Test without offset
443 s.pack_into(writable_buf, 0, test_string)
444 from_buf = writable_buf.tostring()[:len(test_string)]
445 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000446
Benjamin Petersond5299862008-06-11 01:31:28 +0000447 # Test with offset.
448 s.pack_into(writable_buf, 10, test_string)
449 from_buf = writable_buf.tostring()[:len(test_string)+10]
450 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000451
Benjamin Petersond5299862008-06-11 01:31:28 +0000452 # Go beyond boundaries.
453 small_buf = array.array('c', ' '*10)
Benjamin Peterson86ac22e2010-07-07 23:26:57 +0000454 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
455 test_string)
456 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
457 test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000458
Georg Brandl0638a082009-02-13 11:03:59 +0000459 # Test bogus offset (issue 3694)
460 sb = small_buf
Benjamin Peterson0b00b6b2010-07-09 13:33:03 +0000461 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
462 None)
Georg Brandl0638a082009-02-13 11:03:59 +0000463
Benjamin Petersond5299862008-06-11 01:31:28 +0000464 def test_pack_into_fn(self):
465 test_string = 'Reykjavik rocks, eow!'
466 writable_buf = array.array('c', ' '*100)
467 fmt = '21s'
468 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000469
Benjamin Petersond5299862008-06-11 01:31:28 +0000470 # Test without offset.
471 pack_into(writable_buf, 0, test_string)
472 from_buf = writable_buf.tostring()[:len(test_string)]
473 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000474
Benjamin Petersond5299862008-06-11 01:31:28 +0000475 # Test with offset.
476 pack_into(writable_buf, 10, test_string)
477 from_buf = writable_buf.tostring()[:len(test_string)+10]
478 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000479
Benjamin Petersond5299862008-06-11 01:31:28 +0000480 # Go beyond boundaries.
481 small_buf = array.array('c', ' '*10)
Benjamin Peterson86ac22e2010-07-07 23:26:57 +0000482 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
483 test_string)
484 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
485 test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000486
Benjamin Petersond5299862008-06-11 01:31:28 +0000487 def test_unpack_with_buffer(self):
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000488 with check_py3k_warnings(("buffer.. not supported in 3.x",
489 DeprecationWarning)):
490 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
491 data1 = array.array('B', '\x12\x34\x56\x78')
492 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
493 for data in [data1, data2]:
494 value, = struct.unpack('>I', data)
495 self.assertEqual(value, 0x12345678)
496
497 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000498
Benjamin Petersond5299862008-06-11 01:31:28 +0000499 def test_bool(self):
Benjamin Peterson489113f2010-07-07 19:03:36 +0000500 class ExplodingBool(object):
501 def __nonzero__(self):
502 raise IOError
Benjamin Petersond5299862008-06-11 01:31:28 +0000503 for prefix in tuple("<>!=")+('',):
504 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000505 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000506
Benjamin Petersond5299862008-06-11 01:31:28 +0000507 falseFormat = prefix + '?' * len(false)
508 packedFalse = struct.pack(falseFormat, *false)
509 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000510
Benjamin Petersond5299862008-06-11 01:31:28 +0000511 trueFormat = prefix + '?' * len(true)
512 packedTrue = struct.pack(trueFormat, *true)
513 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000514
Benjamin Petersond5299862008-06-11 01:31:28 +0000515 self.assertEqual(len(true), len(unpackedTrue))
516 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000517
Benjamin Petersond5299862008-06-11 01:31:28 +0000518 for t in unpackedFalse:
519 self.assertFalse(t)
520 for t in unpackedTrue:
521 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000522
Benjamin Petersond5299862008-06-11 01:31:28 +0000523 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000524
Benjamin Petersond5299862008-06-11 01:31:28 +0000525 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000526
Benjamin Petersond5299862008-06-11 01:31:28 +0000527 if len(packed) != 1:
528 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
529 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000530
Benjamin Peterson489113f2010-07-07 19:03:36 +0000531 self.assertRaises(IOError, struct.pack, prefix + '?',
532 ExplodingBool())
533
534 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
535 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000536
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000537 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
538 def test_crasher(self):
539 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000540
Mark Dickinson40228912010-06-11 20:27:05 +0000541 def test_count_overflow(self):
542 hugecount = '{}b'.format(sys.maxsize+1)
543 self.assertRaises(struct.error, struct.calcsize, hugecount)
544
545 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
546 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000547
Benjamin Petersond5299862008-06-11 01:31:28 +0000548def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000549 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000550
Benjamin Petersond5299862008-06-11 01:31:28 +0000551if __name__ == '__main__':
552 test_main()