blob: 1877192be85e85763b2813a8508a6a2c80deb250 [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)
65 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
66 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
67 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.
Mark Dickinson5fd3af22009-07-07 15:08:28 +0000246 self.assertRaises(struct.error, pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000247
248 def run(self):
249 from random import randrange
250
251 # Create all interesting powers of 2.
252 values = []
253 for exp in range(self.bitsize + 3):
254 values.append(1L << exp)
255
256 # Add some random values.
257 for i in range(self.bitsize):
258 val = 0L
259 for j in range(self.bytesize):
260 val = (val << 8) | randrange(256)
261 values.append(val)
262
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000263 # Values absorbed from other tests
264 values.extend([300, 700000, sys.maxint*4])
265
266 # Try all those, and their negations, and +-1 from
267 # them. Note that this tests all power-of-2
268 # boundaries in range, and a few out of range, plus
269 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000270 for base in values:
271 for val in -base, base:
272 for incr in -1, 0, 1:
273 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000274 self.test_one(int(x))
275 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000276
277 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000278 class NotAnIntNS(object):
279 def __int__(self):
280 return 42
281
282 def __long__(self):
283 return 1729L
284
285 class NotAnIntOS:
286 def __int__(self):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000287 return 85
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000288
289 def __long__(self):
290 return -163L
291
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000292 # Objects with an '__index__' method should be allowed
293 # to pack as integers. That is assuming the implemented
294 # '__index__' method returns and 'int' or 'long'.
295 class Indexable(object):
296 def __init__(self, value):
297 self._value = value
298
299 def __index__(self):
300 return self._value
301
302 # If the '__index__' method raises a type error, then
303 # '__int__' should be used with a deprecation warning.
304 class BadIndex(object):
305 def __index__(self):
306 raise TypeError
307
308 def __int__(self):
309 return 42
310
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000311 self.assertRaises((TypeError, struct.error),
312 struct.pack, self.format,
313 "a string")
314 self.assertRaises((TypeError, struct.error),
315 struct.pack, self.format,
316 randrange)
317 with check_warnings(("integer argument expected, "
318 "got non-integer", DeprecationWarning)):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000319 self.assertRaises((TypeError, struct.error),
320 struct.pack, self.format,
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000321 3+42j)
Benjamin Petersond5299862008-06-11 01:31:28 +0000322
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000323 # an attempt to convert a non-integer (with an
324 # implicit conversion via __int__) should succeed,
325 # with a DeprecationWarning
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000326 for nonint in NotAnIntNS(), NotAnIntOS(), BadIndex():
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000327 with check_warnings((".*integer argument expected, got non"
328 "-integer", DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000329 got = struct.pack(self.format, nonint)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000330 lineno = inspect.currentframe().f_lineno - 1
331 self.assertEqual(w.filename, testmod_filename)
332 self.assertEqual(w.lineno, lineno)
333 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000334 expected = struct.pack(self.format, int(nonint))
335 self.assertEqual(got, expected)
336
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000337 # Check for legitimate values from '__index__'.
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000338 for obj in (Indexable(0), Indexable(10), Indexable(17),
339 Indexable(42), Indexable(100), Indexable(127)):
340 try:
341 struct.pack(format, obj)
342 except:
343 self.fail("integer code pack failed on object "
344 "with '__index__' method")
345
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000346 # Check for bogus values from '__index__'.
347 for obj in (Indexable('a'), Indexable(u'b'), Indexable(None),
348 Indexable({'a': 1}), Indexable([1, 2, 3])):
349 self.assertRaises((TypeError, struct.error),
350 struct.pack, self.format,
351 obj)
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000352
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000353 byteorders = '', '@', '=', '<', '>', '!'
354 for code in integer_codes:
355 for byteorder in byteorders:
356 if (byteorder in ('', '@') and code in ('q', 'Q') and
357 not HAVE_LONG_LONG):
358 continue
359 format = byteorder+code
360 t = IntTester(format)
361 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000362
363 def test_p_code(self):
364 # Test p ("Pascal string") code.
365 for code, input, expected, expectedback in [
366 ('p','abc', '\x00', ''),
367 ('1p', 'abc', '\x00', ''),
368 ('2p', 'abc', '\x01a', 'a'),
369 ('3p', 'abc', '\x02ab', 'ab'),
370 ('4p', 'abc', '\x03abc', 'abc'),
371 ('5p', 'abc', '\x03abc\x00', 'abc'),
372 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
373 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
374 got = struct.pack(code, input)
375 self.assertEqual(got, expected)
376 (got,) = struct.unpack(code, got)
377 self.assertEqual(got, expectedback)
378
379 def test_705836(self):
380 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
381 # from the low-order discarded bits could propagate into the exponent
382 # field, causing the result to be wrong by a factor of 2.
383 import math
384
385 for base in range(1, 33):
386 # smaller <- largest representable float less than base.
387 delta = 0.5
388 while base - delta / 2.0 != base:
389 delta /= 2.0
390 smaller = base - delta
391 # Packing this rounds away a solid string of trailing 1 bits.
392 packed = struct.pack("<f", smaller)
393 unpacked = struct.unpack("<f", packed)[0]
394 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
395 # 16, respectively.
396 self.assertEqual(base, unpacked)
397 bigpacked = struct.pack(">f", smaller)
398 self.assertEqual(bigpacked, string_reverse(packed))
399 unpacked = struct.unpack(">f", bigpacked)[0]
400 self.assertEqual(base, unpacked)
401
402 # Largest finite IEEE single.
403 big = (1 << 24) - 1
404 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000405 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000406 unpacked = struct.unpack(">f", packed)[0]
407 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000408
Benjamin Petersond5299862008-06-11 01:31:28 +0000409 # The same, but tack on a 1 bit so it rounds up to infinity.
410 big = (1 << 25) - 1
411 big = math.ldexp(big, 127 - 24)
412 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000413
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000414 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000415 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
416 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000417 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000418 self.check_float_coerce(endian + fmt, 1.0)
419 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000420
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000421 def test_unpack_from(self, cls=str):
422 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000423 fmt = '4s'
424 s = struct.Struct(fmt)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000425
426 self.assertEqual(s.unpack_from(data), ('abcd',))
427 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
428 for i in xrange(6):
429 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
430 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
431 for i in xrange(6, len(data) + 1):
432 self.assertRaises(struct.error, s.unpack_from, data, i)
433 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000434
Benjamin Petersond5299862008-06-11 01:31:28 +0000435 def test_pack_into(self):
436 test_string = 'Reykjavik rocks, eow!'
437 writable_buf = array.array('c', ' '*100)
438 fmt = '21s'
439 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000440
Benjamin Petersond5299862008-06-11 01:31:28 +0000441 # Test without offset
442 s.pack_into(writable_buf, 0, test_string)
443 from_buf = writable_buf.tostring()[:len(test_string)]
444 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000445
Benjamin Petersond5299862008-06-11 01:31:28 +0000446 # Test with offset.
447 s.pack_into(writable_buf, 10, test_string)
448 from_buf = writable_buf.tostring()[:len(test_string)+10]
449 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000450
Benjamin Petersond5299862008-06-11 01:31:28 +0000451 # Go beyond boundaries.
452 small_buf = array.array('c', ' '*10)
453 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
454 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000455
Georg Brandl0638a082009-02-13 11:03:59 +0000456 # Test bogus offset (issue 3694)
457 sb = small_buf
458 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
459
Benjamin Petersond5299862008-06-11 01:31:28 +0000460 def test_pack_into_fn(self):
461 test_string = 'Reykjavik rocks, eow!'
462 writable_buf = array.array('c', ' '*100)
463 fmt = '21s'
464 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000465
Benjamin Petersond5299862008-06-11 01:31:28 +0000466 # Test without offset.
467 pack_into(writable_buf, 0, test_string)
468 from_buf = writable_buf.tostring()[:len(test_string)]
469 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000470
Benjamin Petersond5299862008-06-11 01:31:28 +0000471 # Test with offset.
472 pack_into(writable_buf, 10, test_string)
473 from_buf = writable_buf.tostring()[:len(test_string)+10]
474 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000475
Benjamin Petersond5299862008-06-11 01:31:28 +0000476 # Go beyond boundaries.
477 small_buf = array.array('c', ' '*10)
478 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
479 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000480
Benjamin Petersond5299862008-06-11 01:31:28 +0000481 def test_unpack_with_buffer(self):
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000482 with check_py3k_warnings(("buffer.. not supported in 3.x",
483 DeprecationWarning)):
484 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
485 data1 = array.array('B', '\x12\x34\x56\x78')
486 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
487 for data in [data1, data2]:
488 value, = struct.unpack('>I', data)
489 self.assertEqual(value, 0x12345678)
490
491 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000492
Benjamin Petersond5299862008-06-11 01:31:28 +0000493 def test_bool(self):
Benjamin Peterson489113f2010-07-07 19:03:36 +0000494 class ExplodingBool(object):
495 def __nonzero__(self):
496 raise IOError
Benjamin Petersond5299862008-06-11 01:31:28 +0000497 for prefix in tuple("<>!=")+('',):
498 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000499 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000500
Benjamin Petersond5299862008-06-11 01:31:28 +0000501 falseFormat = prefix + '?' * len(false)
502 packedFalse = struct.pack(falseFormat, *false)
503 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000504
Benjamin Petersond5299862008-06-11 01:31:28 +0000505 trueFormat = prefix + '?' * len(true)
506 packedTrue = struct.pack(trueFormat, *true)
507 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000508
Benjamin Petersond5299862008-06-11 01:31:28 +0000509 self.assertEqual(len(true), len(unpackedTrue))
510 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000511
Benjamin Petersond5299862008-06-11 01:31:28 +0000512 for t in unpackedFalse:
513 self.assertFalse(t)
514 for t in unpackedTrue:
515 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000516
Benjamin Petersond5299862008-06-11 01:31:28 +0000517 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000518
Benjamin Petersond5299862008-06-11 01:31:28 +0000519 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000520
Benjamin Petersond5299862008-06-11 01:31:28 +0000521 if len(packed) != 1:
522 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
523 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000524
Benjamin Peterson489113f2010-07-07 19:03:36 +0000525 self.assertRaises(IOError, struct.pack, prefix + '?',
526 ExplodingBool())
527
528 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
529 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000530
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000531 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
532 def test_crasher(self):
533 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000534
Mark Dickinson40228912010-06-11 20:27:05 +0000535 def test_count_overflow(self):
536 hugecount = '{}b'.format(sys.maxsize+1)
537 self.assertRaises(struct.error, struct.calcsize, hugecount)
538
539 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
540 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000541
Benjamin Petersond5299862008-06-11 01:31:28 +0000542def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000543 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000544
Benjamin Petersond5299862008-06-11 01:31:28 +0000545if __name__ == '__main__':
546 test_main()