blob: aacadd6c84f0218f545ac719f9b3b97bc280c141 [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 Brandla4f46e12010-02-07 17:03:15 +00005from test.test_support import run_unittest
Benjamin Petersond5299862008-06-11 01:31:28 +00006
Tim Peters17e17d42001-06-13 22:45:27 +00007import sys
8ISBIGENDIAN = sys.byteorder == "big"
Mark Hammond69ed5242008-08-23 00:59:14 +00009IS32BIT = sys.maxsize == 0x7fffffff
Mark Dickinsonbb3895c2009-07-07 14:15:45 +000010
11integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
12
13# Native 'q' packing isn't available on systems that don't have the C
14# long long type.
15try:
16 struct.pack('q', 5)
17except struct.error:
18 HAVE_LONG_LONG = False
19else:
20 HAVE_LONG_LONG = True
Tim Peters17e17d42001-06-13 22:45:27 +000021
22def string_reverse(s):
Tim Peters852eae12006-06-05 20:48:49 +000023 return "".join(reversed(s))
Tim Peters17e17d42001-06-13 22:45:27 +000024
25def bigendian_to_native(value):
26 if ISBIGENDIAN:
27 return value
28 else:
29 return string_reverse(value)
30
Benjamin Petersond5299862008-06-11 01:31:28 +000031class StructTest(unittest.TestCase):
Barry Warsaw07a0eec1996-12-12 23:34:06 +000032
Benjamin Petersond5299862008-06-11 01:31:28 +000033 def check_float_coerce(self, format, number):
Mark Dickinson154b7ad2010-03-07 16:24:45 +000034 # SF bug 1530559. struct.pack raises TypeError where it used
35 # to convert.
36 with warnings.catch_warnings(record=True) as w:
37 # ignore everything except the
38 # DeprecationWarning we're looking for
39 warnings.simplefilter("ignore")
Mark Dickinson1c0c78c2010-03-05 14:36:20 +000040 warnings.filterwarnings(
Mark Dickinson154b7ad2010-03-07 16:24:45 +000041 "always",
Mark Dickinson1c0c78c2010-03-05 14:36:20 +000042 message=".*integer argument expected, got float",
Mark Dickinson1c0c78c2010-03-05 14:36:20 +000043 category=DeprecationWarning,
Mark Dickinson154b7ad2010-03-07 16:24:45 +000044 module=__name__
45 )
46 got = struct.pack(format, number)
47 nwarn = len(w)
48 self.assertEqual(nwarn, 1,
49 "expected exactly one warning from "
50 "struct.pack({!r}, {!r}); "
51 "got {} warnings".format(
52 format, number, nwarn))
53 expected = struct.pack(format, int(number))
54 self.assertEqual(got, expected)
Tim Peters7a3bfc32001-06-12 01:22:22 +000055
Benjamin Petersond5299862008-06-11 01:31:28 +000056 def test_isbigendian(self):
57 self.assertEqual((struct.pack('=i', 1)[0] == chr(0)), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000058
Benjamin Petersond5299862008-06-11 01:31:28 +000059 def test_consistence(self):
60 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000061
Benjamin Petersond5299862008-06-11 01:31:28 +000062 sz = struct.calcsize('i')
63 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000064
Benjamin Petersond5299862008-06-11 01:31:28 +000065 fmt = 'cbxxxxxxhhhhiillffd?'
66 fmt3 = '3c3b18x12h6i6l6f3d3?'
67 sz = struct.calcsize(fmt)
68 sz3 = struct.calcsize(fmt3)
69 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000070
Benjamin Petersond5299862008-06-11 01:31:28 +000071 self.assertRaises(struct.error, struct.pack, 'iii', 3)
72 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
73 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
74 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
75 self.assertRaises(struct.error, struct.unpack, 'd', 'flap')
76 s = struct.pack('ii', 1, 2)
77 self.assertRaises(struct.error, struct.unpack, 'iii', s)
78 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000079
Benjamin Petersond5299862008-06-11 01:31:28 +000080 def test_transitiveness(self):
81 c = 'a'
82 b = 1
83 h = 255
84 i = 65535
85 l = 65536
86 f = 3.1415
87 d = 3.1415
88 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000089
Benjamin Petersond5299862008-06-11 01:31:28 +000090 for prefix in ('', '@', '<', '>', '=', '!'):
91 for format in ('xcbhilfd?', 'xcBHILfd?'):
92 format = prefix + format
93 s = struct.pack(format, c, b, h, i, l, f, d, t)
94 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
95 self.assertEqual(cp, c)
96 self.assertEqual(bp, b)
97 self.assertEqual(hp, h)
98 self.assertEqual(ip, i)
99 self.assertEqual(lp, l)
100 self.assertEqual(int(100 * fp), int(100 * f))
101 self.assertEqual(int(100 * dp), int(100 * d))
102 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000103
Benjamin Petersond5299862008-06-11 01:31:28 +0000104 def test_new_features(self):
105 # Test some of the new features in detail
106 # (format, argument, big-endian result, little-endian result, asymmetric)
107 tests = [
108 ('c', 'a', 'a', 'a', 0),
109 ('xc', 'a', '\0a', '\0a', 0),
110 ('cx', 'a', 'a\0', 'a\0', 0),
111 ('s', 'a', 'a', 'a', 0),
112 ('0s', 'helloworld', '', '', 1),
113 ('1s', 'helloworld', 'h', 'h', 1),
114 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
115 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
116 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
117 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
118 ('b', 7, '\7', '\7', 0),
119 ('b', -7, '\371', '\371', 0),
120 ('B', 7, '\7', '\7', 0),
121 ('B', 249, '\371', '\371', 0),
122 ('h', 700, '\002\274', '\274\002', 0),
123 ('h', -700, '\375D', 'D\375', 0),
124 ('H', 700, '\002\274', '\274\002', 0),
125 ('H', 0x10000-700, '\375D', 'D\375', 0),
126 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
127 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
128 ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
129 ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
130 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
131 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
132 ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
133 ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
134 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
135 ('d', 2.0, '@\000\000\000\000\000\000\000',
136 '\000\000\000\000\000\000\000@', 0),
137 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
138 ('d', -2.0, '\300\000\000\000\000\000\000\000',
139 '\000\000\000\000\000\000\000\300', 0),
140 ('?', 0, '\0', '\0', 0),
141 ('?', 3, '\1', '\1', 1),
142 ('?', True, '\1', '\1', 0),
143 ('?', [], '\0', '\0', 1),
144 ('?', (1,), '\1', '\1', 1),
145 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000146
Benjamin Petersond5299862008-06-11 01:31:28 +0000147 for fmt, arg, big, lil, asy in tests:
148 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
149 ('='+fmt, ISBIGENDIAN and big or lil)]:
150 res = struct.pack(xfmt, arg)
151 self.assertEqual(res, exp)
152 self.assertEqual(struct.calcsize(xfmt), len(res))
153 rev = struct.unpack(xfmt, res)[0]
154 if rev != arg:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000155 self.assertTrue(asy)
Benjamin Petersond5299862008-06-11 01:31:28 +0000156
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000157 def test_calcsize(self):
158 expected_size = {
159 'b': 1, 'B': 1,
160 'h': 2, 'H': 2,
161 'i': 4, 'I': 4,
162 'l': 4, 'L': 4,
163 'q': 8, 'Q': 8,
164 }
Benjamin Petersond5299862008-06-11 01:31:28 +0000165
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000166 # standard integer sizes
167 for code in integer_codes:
168 for byteorder in ('=', '<', '>', '!'):
169 format = byteorder+code
170 size = struct.calcsize(format)
171 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000172
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000173 # native integer sizes, except 'q' and 'Q'
174 for format_pair in ('bB', 'hH', 'iI', 'lL'):
175 for byteorder in ['', '@']:
176 signed_size = struct.calcsize(byteorder + format_pair[0])
177 unsigned_size = struct.calcsize(byteorder + format_pair[1])
178 self.assertEqual(signed_size, unsigned_size)
179
180 # bounds for native integer sizes
181 self.assertTrue(struct.calcsize('b')==1)
182 self.assertTrue(2 <= struct.calcsize('h'))
183 self.assertTrue(4 <= struct.calcsize('l'))
184 self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
185 self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
186
187 # tests for native 'q' and 'Q' when applicable
188 if HAVE_LONG_LONG:
189 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
190 self.assertTrue(8 <= struct.calcsize('q'))
191 self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
192
193 def test_integers(self):
194 # Integer tests (bBhHiIlLqQ).
Benjamin Petersond5299862008-06-11 01:31:28 +0000195 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000196
Benjamin Petersond5299862008-06-11 01:31:28 +0000197 class IntTester(unittest.TestCase):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000198 def __init__(self, format):
Gregory P. Smith28399852009-03-31 16:54:10 +0000199 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000200 self.format = format
201 self.code = format[-1]
202 self.direction = format[:-1]
203 if not self.direction in ('', '@', '=', '<', '>', '!'):
204 raise ValueError("unrecognized packing direction: %s" %
205 self.direction)
206 self.bytesize = struct.calcsize(format)
207 self.bitsize = self.bytesize * 8
208 if self.code in tuple('bhilq'):
209 self.signed = True
210 self.min_value = -(2L**(self.bitsize-1))
211 self.max_value = 2L**(self.bitsize-1) - 1
212 elif self.code in tuple('BHILQ'):
213 self.signed = False
214 self.min_value = 0
215 self.max_value = 2L**self.bitsize - 1
216 else:
217 raise ValueError("unrecognized format code: %s" %
218 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000219
Benjamin Petersond5299862008-06-11 01:31:28 +0000220 def test_one(self, x, pack=struct.pack,
221 unpack=struct.unpack,
222 unhexlify=binascii.unhexlify):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000223
224 format = self.format
225 if self.min_value <= x <= self.max_value:
Benjamin Petersond5299862008-06-11 01:31:28 +0000226 expected = long(x)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000227 if self.signed and x < 0:
Benjamin Petersond5299862008-06-11 01:31:28 +0000228 expected += 1L << self.bitsize
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000229 self.assertTrue(expected >= 0)
230 expected = '%x' % expected
Benjamin Petersond5299862008-06-11 01:31:28 +0000231 if len(expected) & 1:
232 expected = "0" + expected
233 expected = unhexlify(expected)
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000234 expected = ("\x00" * (self.bytesize - len(expected)) +
235 expected)
236 if (self.direction == '<' or
237 self.direction in ('', '@', '=') and not ISBIGENDIAN):
238 expected = string_reverse(expected)
239 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000240
Benjamin Petersond5299862008-06-11 01:31:28 +0000241 # Pack work?
242 got = pack(format, x)
243 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000244
Benjamin Petersond5299862008-06-11 01:31:28 +0000245 # Unpack work?
246 retrieved = unpack(format, got)[0]
247 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000248
Benjamin Petersond5299862008-06-11 01:31:28 +0000249 # Adding any byte should cause a "too big" error.
250 self.assertRaises((struct.error, TypeError), unpack, format,
251 '\x01' + got)
Benjamin Petersond5299862008-06-11 01:31:28 +0000252 else:
253 # x is out of range -- verify pack realizes that.
Mark Dickinson5fd3af22009-07-07 15:08:28 +0000254 self.assertRaises(struct.error, pack, format, x)
Benjamin Petersond5299862008-06-11 01:31:28 +0000255
256 def run(self):
257 from random import randrange
258
259 # Create all interesting powers of 2.
260 values = []
261 for exp in range(self.bitsize + 3):
262 values.append(1L << exp)
263
264 # Add some random values.
265 for i in range(self.bitsize):
266 val = 0L
267 for j in range(self.bytesize):
268 val = (val << 8) | randrange(256)
269 values.append(val)
270
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000271 # Values absorbed from other tests
272 values.extend([300, 700000, sys.maxint*4])
273
274 # Try all those, and their negations, and +-1 from
275 # them. Note that this tests all power-of-2
276 # boundaries in range, and a few out of range, plus
277 # +-(2**n +- 1).
Benjamin Petersond5299862008-06-11 01:31:28 +0000278 for base in values:
279 for val in -base, base:
280 for incr in -1, 0, 1:
281 x = val + incr
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000282 self.test_one(int(x))
283 self.test_one(long(x))
Benjamin Petersond5299862008-06-11 01:31:28 +0000284
285 # Some error cases.
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000286 class NotAnIntNS(object):
287 def __int__(self):
288 return 42
289
290 def __long__(self):
291 return 1729L
292
293 class NotAnIntOS:
294 def __int__(self):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000295 return 85
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000296
297 def __long__(self):
298 return -163L
299
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000300 for badobject in ("a string", 3+42j, randrange):
301 self.assertRaises((TypeError, struct.error),
302 struct.pack, self.format,
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000303 badobject)
Benjamin Petersond5299862008-06-11 01:31:28 +0000304
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000305 # an attempt to convert a non-integer (with an
306 # implicit conversion via __int__) should succeed,
307 # with a DeprecationWarning
308 for nonint in NotAnIntNS(), NotAnIntOS():
309 with warnings.catch_warnings(record=True) as w:
310 # ignore everything except the
311 # DeprecationWarning we're looking for
312 warnings.simplefilter("ignore")
313 warnings.filterwarnings(
314 "always",
315 message=(".*integer argument expected, "
316 "got non-integer.*"),
317 category=DeprecationWarning,
318 module=__name__
319 )
320 got = struct.pack(self.format, nonint)
321 nwarn = len(w)
322 self.assertEqual(nwarn, 1,
323 "expected exactly one warning from "
324 "struct.pack({!r}, {!r}); "
325 "got {} warnings".format(
326 self.format, nonint, nwarn))
327 expected = struct.pack(self.format, int(nonint))
328 self.assertEqual(got, expected)
329
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000330 byteorders = '', '@', '=', '<', '>', '!'
331 for code in integer_codes:
332 for byteorder in byteorders:
333 if (byteorder in ('', '@') and code in ('q', 'Q') and
334 not HAVE_LONG_LONG):
335 continue
336 format = byteorder+code
337 t = IntTester(format)
338 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000339
340 def test_p_code(self):
341 # Test p ("Pascal string") code.
342 for code, input, expected, expectedback in [
343 ('p','abc', '\x00', ''),
344 ('1p', 'abc', '\x00', ''),
345 ('2p', 'abc', '\x01a', 'a'),
346 ('3p', 'abc', '\x02ab', 'ab'),
347 ('4p', 'abc', '\x03abc', 'abc'),
348 ('5p', 'abc', '\x03abc\x00', 'abc'),
349 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
350 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
351 got = struct.pack(code, input)
352 self.assertEqual(got, expected)
353 (got,) = struct.unpack(code, got)
354 self.assertEqual(got, expectedback)
355
356 def test_705836(self):
357 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
358 # from the low-order discarded bits could propagate into the exponent
359 # field, causing the result to be wrong by a factor of 2.
360 import math
361
362 for base in range(1, 33):
363 # smaller <- largest representable float less than base.
364 delta = 0.5
365 while base - delta / 2.0 != base:
366 delta /= 2.0
367 smaller = base - delta
368 # Packing this rounds away a solid string of trailing 1 bits.
369 packed = struct.pack("<f", smaller)
370 unpacked = struct.unpack("<f", packed)[0]
371 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
372 # 16, respectively.
373 self.assertEqual(base, unpacked)
374 bigpacked = struct.pack(">f", smaller)
375 self.assertEqual(bigpacked, string_reverse(packed))
376 unpacked = struct.unpack(">f", bigpacked)[0]
377 self.assertEqual(base, unpacked)
378
379 # Largest finite IEEE single.
380 big = (1 << 24) - 1
381 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000382 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000383 unpacked = struct.unpack(">f", packed)[0]
384 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000385
Benjamin Petersond5299862008-06-11 01:31:28 +0000386 # The same, but tack on a 1 bit so it rounds up to infinity.
387 big = (1 << 25) - 1
388 big = math.ldexp(big, 127 - 24)
389 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000390
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000391 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000392 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
393 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000394 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000395 self.check_float_coerce(endian + fmt, 1.0)
396 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000397
Benjamin Petersond5299862008-06-11 01:31:28 +0000398 def test_unpack_from(self):
399 test_string = 'abcd01234'
400 fmt = '4s'
401 s = struct.Struct(fmt)
402 for cls in (str, buffer):
403 data = cls(test_string)
404 self.assertEqual(s.unpack_from(data), ('abcd',))
405 self.assertEqual(s.unpack_from(data, 2), ('cd01',))
406 self.assertEqual(s.unpack_from(data, 4), ('0123',))
407 for i in xrange(6):
408 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
409 for i in xrange(6, len(test_string) + 1):
410 self.assertRaises(struct.error, s.unpack_from, data, i)
411 for cls in (str, buffer):
412 data = cls(test_string)
413 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
414 self.assertEqual(struct.unpack_from(fmt, data, 2), ('cd01',))
415 self.assertEqual(struct.unpack_from(fmt, data, 4), ('0123',))
416 for i in xrange(6):
417 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
418 for i in xrange(6, len(test_string) + 1):
419 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000420
Benjamin Petersond5299862008-06-11 01:31:28 +0000421 def test_pack_into(self):
422 test_string = 'Reykjavik rocks, eow!'
423 writable_buf = array.array('c', ' '*100)
424 fmt = '21s'
425 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000426
Benjamin Petersond5299862008-06-11 01:31:28 +0000427 # Test without offset
428 s.pack_into(writable_buf, 0, test_string)
429 from_buf = writable_buf.tostring()[:len(test_string)]
430 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000431
Benjamin Petersond5299862008-06-11 01:31:28 +0000432 # Test with offset.
433 s.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)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000436
Benjamin Petersond5299862008-06-11 01:31:28 +0000437 # Go beyond boundaries.
438 small_buf = array.array('c', ' '*10)
439 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
440 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000441
Georg Brandl0638a082009-02-13 11:03:59 +0000442 # Test bogus offset (issue 3694)
443 sb = small_buf
444 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
445
Benjamin Petersond5299862008-06-11 01:31:28 +0000446 def test_pack_into_fn(self):
447 test_string = 'Reykjavik rocks, eow!'
448 writable_buf = array.array('c', ' '*100)
449 fmt = '21s'
450 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000451
Benjamin Petersond5299862008-06-11 01:31:28 +0000452 # Test without offset.
453 pack_into(writable_buf, 0, test_string)
454 from_buf = writable_buf.tostring()[:len(test_string)]
455 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000456
Benjamin Petersond5299862008-06-11 01:31:28 +0000457 # Test with offset.
458 pack_into(writable_buf, 10, test_string)
459 from_buf = writable_buf.tostring()[:len(test_string)+10]
460 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000461
Benjamin Petersond5299862008-06-11 01:31:28 +0000462 # Go beyond boundaries.
463 small_buf = array.array('c', ' '*10)
464 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
465 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000466
Benjamin Petersond5299862008-06-11 01:31:28 +0000467 def test_unpack_with_buffer(self):
468 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
469 data1 = array.array('B', '\x12\x34\x56\x78')
470 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
471 for data in [data1, data2]:
472 value, = struct.unpack('>I', data)
473 self.assertEqual(value, 0x12345678)
Martin Blais2856e5f2006-05-26 12:03:27 +0000474
Benjamin Petersond5299862008-06-11 01:31:28 +0000475 def test_bool(self):
476 for prefix in tuple("<>!=")+('',):
477 false = (), [], [], '', 0
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000478 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
Martin Blais2856e5f2006-05-26 12:03:27 +0000479
Benjamin Petersond5299862008-06-11 01:31:28 +0000480 falseFormat = prefix + '?' * len(false)
481 packedFalse = struct.pack(falseFormat, *false)
482 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000483
Benjamin Petersond5299862008-06-11 01:31:28 +0000484 trueFormat = prefix + '?' * len(true)
485 packedTrue = struct.pack(trueFormat, *true)
486 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000487
Benjamin Petersond5299862008-06-11 01:31:28 +0000488 self.assertEqual(len(true), len(unpackedTrue))
489 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000490
Benjamin Petersond5299862008-06-11 01:31:28 +0000491 for t in unpackedFalse:
492 self.assertFalse(t)
493 for t in unpackedTrue:
494 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000495
Benjamin Petersond5299862008-06-11 01:31:28 +0000496 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000497
Benjamin Petersond5299862008-06-11 01:31:28 +0000498 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000499
Benjamin Petersond5299862008-06-11 01:31:28 +0000500 if len(packed) != 1:
501 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
502 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000503
Benjamin Petersond5299862008-06-11 01:31:28 +0000504 for c in '\x01\x7f\xff\x0f\xf0':
505 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000506
Gregory P. Smitha0205d02008-06-14 17:34:09 +0000507 if IS32BIT:
508 def test_crasher(self):
Gregory P. Smith9d534572008-06-11 07:41:16 +0000509 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000510
511
Tim Petersf733abb2007-01-30 03:03:46 +0000512
Benjamin Petersond5299862008-06-11 01:31:28 +0000513def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000514 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000515
Benjamin Petersond5299862008-06-11 01:31:28 +0000516if __name__ == '__main__':
517 test_main()