blob: 4811974970ecf20a394cc5d94df3f0ecab57221b [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
Martin v. Löwisc02e1e62012-07-29 16:30:50 +02006from test import test_support as support
7from test.test_support import (check_warnings, check_py3k_warnings)
Benjamin Petersond5299862008-06-11 01:31:28 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +000011IS32BIT = sys.maxsize == 0x7fffffff
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000012
13integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
14
Florent Xiclunadb4a3212010-03-20 22:21:02 +000015testmod_filename = os.path.splitext(__file__)[0] + '.py'
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000016# Native 'q' packing isn't available on systems that don't have the C
17# long long type.
18try:
19 struct.pack('q', 5)
20except struct.error:
21 HAVE_LONG_LONG = False
22else:
23 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000024
25def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000026 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000027
28def bigendian_to_native(value):
29 if ISBIGENDIAN:
30 return value
31 else:
32 return string_reverse(value)
33
Benjamin Petersond5299862008-06-11 01:31:28 +000034class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000035
Benjamin Petersond5299862008-06-11 01:31:28 +000036 def check_float_coerce(self, format, number):
Mark Dickinson154b7ad2010-03-07 16:24:45 +000037 # SF bug 1530559. struct.pack raises TypeError where it used
38 # to convert.
Florent Xiclunadb4a3212010-03-20 22:21:02 +000039 with check_warnings((".*integer argument expected, got float",
40 DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +000041 got = struct.pack(format, number)
Florent Xiclunadb4a3212010-03-20 22:21:02 +000042 lineno = inspect.currentframe().f_lineno - 1
43 self.assertEqual(w.filename, testmod_filename)
44 self.assertEqual(w.lineno, lineno)
45 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +000046 expected = struct.pack(format, int(number))
47 self.assertEqual(got, expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +000048
Benjamin Petersond5299862008-06-11 01:31:28 +000049 def test_isbigendian(self):
50 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000051
Benjamin Petersond5299862008-06-11 01:31:28 +000052 def test_consistence(self):
53 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000054
Benjamin Petersond5299862008-06-11 01:31:28 +000055 sz = struct.calcsize('i')
56 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Benjamin Petersond5299862008-06-11 01:31:28 +000058 fmt = 'cbxxxxxxhhhhiillffd?'
59 fmt3 = '3c3b18x12h6i6l6f3d3?'
60 sz = struct.calcsize(fmt)
61 sz3 = struct.calcsize(fmt3)
62 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000063
Benjamin Petersond5299862008-06-11 01:31:28 +000064 self.assertRaises(struct.error, struct.pack, 'iii', 3)
65 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Peterson0b00b6b2010-07-09 13:33:03 +000066 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
67 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Benjamin Petersond5299862008-06-11 01:31:28 +000068 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
69 s = struct.pack('ii', 1, 2)
70 self.assertRaises(struct.error, struct.unpack, 'iii', s)
71 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000072
Benjamin Petersond5299862008-06-11 01:31:28 +000073 def test_transitiveness(self):
74 c = 'a'
75 b = 1
76 h = 255
77 i = 65535
78 l = 65536
79 f = 3.1415
80 d = 3.1415
81 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000082
Benjamin Petersond5299862008-06-11 01:31:28 +000083 for prefix in ('', '@', '<', '>', '=', '!'):
84 for format in ('xcbhilfd?', 'xcBHILfd?'):
85 format = prefix + format
86 s = struct.pack(format, c, b, h, i, l, f, d, t)
87 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
88 self.assertEqual(cp, c)
89 self.assertEqual(bp, b)
90 self.assertEqual(hp, h)
91 self.assertEqual(ip, i)
92 self.assertEqual(lp, l)
93 self.assertEqual(int(100 * fp), int(100 * f))
94 self.assertEqual(int(100 * dp), int(100 * d))
95 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000096
Benjamin Petersond5299862008-06-11 01:31:28 +000097 def test_new_features(self):
98 # Test some of the new features in detail
99 # (format, argument, big-endian result, little-endian result, asymmetric)
100 tests = [
101 ('c', 'a', 'a', 'a', 0),
102 ('xc', 'a', '\0a', '\0a', 0),
103 ('cx', 'a', 'a\0', 'a\0', 0),
104 ('s', 'a', 'a', 'a', 0),
105 ('0s', 'helloworld', '', '', 1),
106 ('1s', 'helloworld', 'h', 'h', 1),
107 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
108 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
109 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
110 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
111 ('b', 7, '\7', '\7', 0),
112 ('b', -7, '\371', '\371', 0),
113 ('B', 7, '\7', '\7', 0),
114 ('B', 249, '\371', '\371', 0),
115 ('h', 700, '\002\274', '\274\002', 0),
116 ('h', -700, '\375D', 'D\375', 0),
117 ('H', 700, '\002\274', '\274\002', 0),
118 ('H', 0x10000-700, '\375D', 'D\375', 0),
119 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
120 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
121 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
122 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
123 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
124 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
125 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
126 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
127 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
128 ('d', 2.0, '@\000\000\000\000\000\000\000',
129 '\000\000\000\000\000\000\000@', 0),
130 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
131 ('d', -2.0, '\300\000\000\000\000\000\000\000',
132 '\000\000\000\000\000\000\000\300', 0),
133 ('?', 0, '\0', '\0', 0),
134 ('?', 3, '\1', '\1', 1),
135 ('?', True, '\1', '\1', 0),
136 ('?', [], '\0', '\0', 1),
137 ('?', (1,), '\1', '\1', 1),
138 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000139
Benjamin Petersond5299862008-06-11 01:31:28 +0000140 for fmt, arg, big, lil, asy in tests:
141 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
142 ('='+fmt, ISBIGENDIAN and big or lil)]:
143 res = struct.pack(xfmt, arg)
144 self.assertEqual(res, exp)
145 self.assertEqual(struct.calcsize(xfmt), len(res))
146 rev = struct.unpack(xfmt, res)[0]
147 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000148 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000149
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000150 def test_calcsize(self):
151 expected_size = {
152 'b': 1, 'B': 1,
153 'h': 2, 'H': 2,
154 'i': 4, 'I': 4,
155 'l': 4, 'L': 4,
156 'q': 8, 'Q': 8,
157 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000158
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000159 # standard integer sizes
160 for code in integer_codes:
161 for byteorder in ('=', '<', '>', '!'):
162 format = byteorder+code
163 size = struct.calcsize(format)
164 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000165
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000166 # native integer sizes, except 'q' and 'Q'
167 for format_pair in ('bB', 'hH', 'iI', 'lL'):
168 for byteorder in ['', '@']:
169 signed_size = struct.calcsize(byteorder + format_pair[0])
170 unsigned_size = struct.calcsize(byteorder + format_pair[1])
171 self.assertEqual(signed_size, unsigned_size)
172
173 # bounds for native integer sizes
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000174 self.assertEqual(struct.calcsize('b'), 1)
175 self.assertLessEqual(2, struct.calcsize('h'))
176 self.assertLessEqual(4, struct.calcsize('l'))
177 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
178 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000179
180 # tests for native 'q' and 'Q' when applicable
181 if HAVE_LONG_LONG:
182 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000183 self.assertLessEqual(8, struct.calcsize('q'))
184 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000185
186 def test_integers(self):
187 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000188 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000189
Benjamin Petersond5299862008-06-11 01:31:28 +0000190 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000191 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000192 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000193 self.format = format
194 self.code = format[-1]
195 self.direction = format[:-1]
196 if not self.direction in ('', '@', '=', '<', '>', '!'):
197 raise ValueError("unrecognized packing direction: %s" %
198 self.direction)
199 self.bytesize = struct.calcsize(format)
200 self.bitsize = self.bytesize * 8
201 if self.code in tuple('bhilq'):
202 self.signed = True
203 self.min_value = -(2L**(self.bitsize-1))
204 self.max_value = 2L**(self.bitsize-1) - 1
205 elif self.code in tuple('BHILQ'):
206 self.signed = False
207 self.min_value = 0
208 self.max_value = 2L**self.bitsize - 1
209 else:
210 raise ValueError("unrecognized format code: %s" %
211 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000212
Benjamin Petersond5299862008-06-11 01:31:28 +0000213 def test_one(self, x, pack=struct.pack,
214 unpack=struct.unpack,
215 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000216
217 format = self.format
218 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000219 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000220 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000221 expected += 1L << self.bitsize
Ezio Melottia28eb1c2010-04-04 07:00:02 +0000222 self.assertGreaterEqual(expected, 0)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000223 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000224 if len(expected) & 1:
225 expected = "0" + expected
226 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000227 expected = ("\x00" * (self.bytesize - len(expected)) +
228 expected)
229 if (self.direction == '<' or
230 self.direction in ('', '@', '=') and not ISBIGENDIAN):
231 expected = string_reverse(expected)
232 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000233
Benjamin Petersond5299862008-06-11 01:31:28 +0000234 # Pack work?
235 got = pack(format, x)
236 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000237
Benjamin Petersond5299862008-06-11 01:31:28 +0000238 # Unpack work?
239 retrieved = unpack(format, got)[0]
240 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000241
Benjamin Petersond5299862008-06-11 01:31:28 +0000242 # Adding any byte should cause a "too big" error.
243 self.assertRaises((struct.error, TypeError), unpack, format,
244 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000245 else:
246 # x is out of range -- verify pack realizes that.
Benjamin Peterson9d8c4562010-07-10 15:17:08 +0000247 self.assertRaises((OverflowError, ValueError, struct.error),
248 pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000249
250 def run(self):
251 from random import randrange
252
253 # Create all interesting powers of 2.
254 values = []
255 for exp in range(self.bitsize + 3):
256 values.append(1L << exp)
257
258 # Add some random values.
259 for i in range(self.bitsize):
260 val = 0L
261 for j in range(self.bytesize):
262 val = (val << 8) | randrange(256)
263 values.append(val)
264
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000265 # Values absorbed from other tests
266 values.extend([300, 700000, sys.maxint*4])
267
268 # Try all those, and their negations, and +-1 from
269 # them. Note that this tests all power-of-2
270 # boundaries in range, and a few out of range, plus
271 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000272 for base in values:
273 for val in -base, base:
274 for incr in -1, 0, 1:
275 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000276 self.test_one(int(x))
277 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000278
279 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000280 class NotAnIntNS(object):
281 def __int__(self):
282 return 42
283
284 def __long__(self):
285 return 1729L
286
287 class NotAnIntOS:
288 def __int__(self):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000289 return 85
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000290
291 def __long__(self):
292 return -163L
293
Mark Dickinsonfdaaa9c2010-04-04 08:43:04 +0000294 # Objects with an '__index__' method should be allowed
295 # to pack as integers. That is assuming the implemented
296 # '__index__' method returns and 'int' or 'long'.
297 class Indexable(object):
298 def __init__(self, value):
299 self._value = value
300
301 def __index__(self):
302 return self._value
303
304 # If the '__index__' method raises a type error, then
305 # '__int__' should be used with a deprecation warning.
306 class BadIndex(object):
307 def __index__(self):
308 raise TypeError
309
310 def __int__(self):
311 return 42
312
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000313 self.assertRaises((TypeError, struct.error),
314 struct.pack, self.format,
315 "a string")
316 self.assertRaises((TypeError, struct.error),
317 struct.pack, self.format,
318 randrange)
319 with check_warnings(("integer argument expected, "
320 "got non-integer", DeprecationWarning)):
Benjamin Peterson8e93f4e2010-07-09 18:15:28 +0000321 with self.assertRaises((TypeError, struct.error)):
322 struct.pack(self.format, 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
Kristján Valur Jónsson9795ca42013-03-19 17:17:47 -0700499 def test_unpack_with_memoryview(self):
Benjamin Peterson17feac72013-03-20 13:11:04 -0500500 # Bug 10212: struct.unpack doesn't support new buffer protocol objects
Benjamin Petersonb2c57a92013-03-20 13:10:41 -0500501 data1 = memoryview('\x12\x34\x56\x78')
502 for data in [data1,]:
503 value, = struct.unpack('>I', data)
504 self.assertEqual(value, 0x12345678)
505 self.test_unpack_from(cls=memoryview)
Kristján Valur Jónsson9795ca42013-03-19 17:17:47 -0700506
Benjamin Petersond5299862008-06-11 01:31:28 +0000507 def test_bool(self):
Benjamin Peterson489113f2010-07-07 19:03:36 +0000508 class ExplodingBool(object):
509 def __nonzero__(self):
510 raise IOError
Benjamin Petersond5299862008-06-11 01:31:28 +0000511 for prefix in tuple("<>!=")+('',):
512 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000513 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000514
Benjamin Petersond5299862008-06-11 01:31:28 +0000515 falseFormat = prefix + '?' * len(false)
516 packedFalse = struct.pack(falseFormat, *false)
517 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000518
Benjamin Petersond5299862008-06-11 01:31:28 +0000519 trueFormat = prefix + '?' * len(true)
520 packedTrue = struct.pack(trueFormat, *true)
521 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000522
Benjamin Petersond5299862008-06-11 01:31:28 +0000523 self.assertEqual(len(true), len(unpackedTrue))
524 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000525
Benjamin Petersond5299862008-06-11 01:31:28 +0000526 for t in unpackedFalse:
527 self.assertFalse(t)
528 for t in unpackedTrue:
529 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000530
Benjamin Petersond5299862008-06-11 01:31:28 +0000531 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000532
Benjamin Petersond5299862008-06-11 01:31:28 +0000533 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000534
Benjamin Petersond5299862008-06-11 01:31:28 +0000535 if len(packed) != 1:
536 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
537 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000538
Benjamin Peterson489113f2010-07-07 19:03:36 +0000539 self.assertRaises(IOError, struct.pack, prefix + '?',
540 ExplodingBool())
541
542 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
543 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000544
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000545 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
546 def test_crasher(self):
547 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000548
Mark Dickinson40228912010-06-11 20:27:05 +0000549 def test_count_overflow(self):
550 hugecount = '{}b'.format(sys.maxsize+1)
551 self.assertRaises(struct.error, struct.calcsize, hugecount)
552
553 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
554 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Tim Petersf733abb2007-01-30 03:03:46 +0000555
Martin v. Löwisc02e1e62012-07-29 16:30:50 +0200556 def check_sizeof(self, format_str, number_of_codes):
557 # The size of 'PyStructObject'
558 totalsize = support.calcobjsize('5P')
559 # The size taken up by the 'formatcode' dynamic array
560 totalsize += struct.calcsize('3P') * (number_of_codes + 1)
561 support.check_sizeof(self, struct.Struct(format_str), totalsize)
562
563 @support.cpython_only
Meador Inge68123462012-07-28 21:58:44 -0500564 def test__sizeof__(self):
565 for code in integer_codes:
566 self.check_sizeof(code, 1)
567 self.check_sizeof('BHILfdspP', 9)
568 self.check_sizeof('B' * 1234, 1234)
569 self.check_sizeof('fd', 2)
570 self.check_sizeof('xxxxxxxxxxxxxx', 0)
571 self.check_sizeof('100H', 100)
572 self.check_sizeof('187s', 1)
573 self.check_sizeof('20p', 1)
574 self.check_sizeof('0s', 1)
575 self.check_sizeof('0c', 0)
Meador Inge87c5b942012-07-23 09:27:00 -0500576
Serhiy Storchaka5493d5e2013-12-08 17:44:50 +0200577 def test_unicode_format(self):
578 try:
579 unicode
580 except NameError:
581 self.skipTest('no unicode support')
582 # Issue #19099
583 s = struct.Struct(unichr(ord('I')))
584 self.assertEqual(s.format, 'I')
585 self.assertIs(type(s.format), str)
586 self.assertRaises(ValueError, struct.Struct, unichr(0x80))
587
588
Benjamin Petersond5299862008-06-11 01:31:28 +0000589def test_main():
Martin v. Löwisc02e1e62012-07-29 16:30:50 +0200590 support.run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000591
Benjamin Petersond5299862008-06-11 01:31:28 +0000592if __name__ == '__main__':
593 test_main()