blob: 3e7b259c969bb3c4cba909865a2bf622b12ca630 [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
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000292 self.assertRaises((TypeError, struct.error),
293 struct.pack, self.format,
294 "a string")
295 self.assertRaises((TypeError, struct.error),
296 struct.pack, self.format,
297 randrange)
298 with check_warnings(("integer argument expected, "
299 "got non-integer", DeprecationWarning)):
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000300 self.assertRaises((TypeError, struct.error),
301 struct.pack, self.format,
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000302 3+42j)
Benjamin Petersond5299862008-06-11 01:31:28 +0000303
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000304 # an attempt to convert a non-integer (with an
305 # implicit conversion via __int__) should succeed,
306 # with a DeprecationWarning
307 for nonint in NotAnIntNS(), NotAnIntOS():
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000308 with check_warnings((".*integer argument expected, got non"
309 "-integer", DeprecationWarning)) as w:
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000310 got = struct.pack(self.format, nonint)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000311 lineno = inspect.currentframe().f_lineno - 1
312 self.assertEqual(w.filename, testmod_filename)
313 self.assertEqual(w.lineno, lineno)
314 self.assertEqual(len(w.warnings), 1)
Mark Dickinson154b7ad2010-03-07 16:24:45 +0000315 expected = struct.pack(self.format, int(nonint))
316 self.assertEqual(got, expected)
317
Mark Dickinson4846a8e2010-04-03 14:05:10 +0000318 # Objects with an '__index__' method should be allowed
319 # to pack as integers.
320 class Indexable(object):
321 def __init__(self, value):
322 self._value = value
323
324 def __index__(self):
325 return self._value
326
327 for obj in (Indexable(0), Indexable(10), Indexable(17),
328 Indexable(42), Indexable(100), Indexable(127)):
329 try:
330 struct.pack(format, obj)
331 except:
332 self.fail("integer code pack failed on object "
333 "with '__index__' method")
334
335
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000336 byteorders = '', '@', '=', '<', '>', '!'
337 for code in integer_codes:
338 for byteorder in byteorders:
339 if (byteorder in ('', '@') and code in ('q', 'Q') and
340 not HAVE_LONG_LONG):
341 continue
342 format = byteorder+code
343 t = IntTester(format)
344 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000345
346 def test_p_code(self):
347 # Test p ("Pascal string") code.
348 for code, input, expected, expectedback in [
349 ('p','abc', '\x00', ''),
350 ('1p', 'abc', '\x00', ''),
351 ('2p', 'abc', '\x01a', 'a'),
352 ('3p', 'abc', '\x02ab', 'ab'),
353 ('4p', 'abc', '\x03abc', 'abc'),
354 ('5p', 'abc', '\x03abc\x00', 'abc'),
355 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
356 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
357 got = struct.pack(code, input)
358 self.assertEqual(got, expected)
359 (got,) = struct.unpack(code, got)
360 self.assertEqual(got, expectedback)
361
362 def test_705836(self):
363 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
364 # from the low-order discarded bits could propagate into the exponent
365 # field, causing the result to be wrong by a factor of 2.
366 import math
367
368 for base in range(1, 33):
369 # smaller <- largest representable float less than base.
370 delta = 0.5
371 while base - delta / 2.0 != base:
372 delta /= 2.0
373 smaller = base - delta
374 # Packing this rounds away a solid string of trailing 1 bits.
375 packed = struct.pack("<f", smaller)
376 unpacked = struct.unpack("<f", packed)[0]
377 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
378 # 16, respectively.
379 self.assertEqual(base, unpacked)
380 bigpacked = struct.pack(">f", smaller)
381 self.assertEqual(bigpacked, string_reverse(packed))
382 unpacked = struct.unpack(">f", bigpacked)[0]
383 self.assertEqual(base, unpacked)
384
385 # Largest finite IEEE single.
386 big = (1 << 24) - 1
387 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000388 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000389 unpacked = struct.unpack(">f", packed)[0]
390 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000391
Benjamin Petersond5299862008-06-11 01:31:28 +0000392 # The same, but tack on a 1 bit so it rounds up to infinity.
393 big = (1 << 25) - 1
394 big = math.ldexp(big, 127 - 24)
395 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000396
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000397 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000398 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
399 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000400 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000401 self.check_float_coerce(endian + fmt, 1.0)
402 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000403
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000404 def test_unpack_from(self, cls=str):
405 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000406 fmt = '4s'
407 s = struct.Struct(fmt)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000408
409 self.assertEqual(s.unpack_from(data), ('abcd',))
410 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
411 for i in xrange(6):
412 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
413 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
414 for i in xrange(6, len(data) + 1):
415 self.assertRaises(struct.error, s.unpack_from, data, i)
416 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000417
Benjamin Petersond5299862008-06-11 01:31:28 +0000418 def test_pack_into(self):
419 test_string = 'Reykjavik rocks, eow!'
420 writable_buf = array.array('c', ' '*100)
421 fmt = '21s'
422 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000423
Benjamin Petersond5299862008-06-11 01:31:28 +0000424 # Test without offset
425 s.pack_into(writable_buf, 0, test_string)
426 from_buf = writable_buf.tostring()[:len(test_string)]
427 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000428
Benjamin Petersond5299862008-06-11 01:31:28 +0000429 # Test with offset.
430 s.pack_into(writable_buf, 10, test_string)
431 from_buf = writable_buf.tostring()[:len(test_string)+10]
432 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000433
Benjamin Petersond5299862008-06-11 01:31:28 +0000434 # Go beyond boundaries.
435 small_buf = array.array('c', ' '*10)
436 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
437 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000438
Georg Brandl0638a082009-02-13 11:03:59 +0000439 # Test bogus offset (issue 3694)
440 sb = small_buf
441 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
442
Benjamin Petersond5299862008-06-11 01:31:28 +0000443 def test_pack_into_fn(self):
444 test_string = 'Reykjavik rocks, eow!'
445 writable_buf = array.array('c', ' '*100)
446 fmt = '21s'
447 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000448
Benjamin Petersond5299862008-06-11 01:31:28 +0000449 # Test without offset.
450 pack_into(writable_buf, 0, test_string)
451 from_buf = writable_buf.tostring()[:len(test_string)]
452 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000453
Benjamin Petersond5299862008-06-11 01:31:28 +0000454 # Test with offset.
455 pack_into(writable_buf, 10, test_string)
456 from_buf = writable_buf.tostring()[:len(test_string)+10]
457 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000458
Benjamin Petersond5299862008-06-11 01:31:28 +0000459 # Go beyond boundaries.
460 small_buf = array.array('c', ' '*10)
461 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
462 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000463
Benjamin Petersond5299862008-06-11 01:31:28 +0000464 def test_unpack_with_buffer(self):
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000465 with check_py3k_warnings(("buffer.. not supported in 3.x",
466 DeprecationWarning)):
467 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
468 data1 = array.array('B', '\x12\x34\x56\x78')
469 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
470 for data in [data1, data2]:
471 value, = struct.unpack('>I', data)
472 self.assertEqual(value, 0x12345678)
473
474 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000475
Benjamin Petersond5299862008-06-11 01:31:28 +0000476 def test_bool(self):
477 for prefix in tuple("<>!=")+('',):
478 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000479 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000480
Benjamin Petersond5299862008-06-11 01:31:28 +0000481 falseFormat = prefix + '?' * len(false)
482 packedFalse = struct.pack(falseFormat, *false)
483 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000484
Benjamin Petersond5299862008-06-11 01:31:28 +0000485 trueFormat = prefix + '?' * len(true)
486 packedTrue = struct.pack(trueFormat, *true)
487 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000488
Benjamin Petersond5299862008-06-11 01:31:28 +0000489 self.assertEqual(len(true), len(unpackedTrue))
490 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000491
Benjamin Petersond5299862008-06-11 01:31:28 +0000492 for t in unpackedFalse:
493 self.assertFalse(t)
494 for t in unpackedTrue:
495 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000496
Benjamin Petersond5299862008-06-11 01:31:28 +0000497 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000498
Benjamin Petersond5299862008-06-11 01:31:28 +0000499 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000500
Benjamin Petersond5299862008-06-11 01:31:28 +0000501 if len(packed) != 1:
502 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
503 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000504
Benjamin Petersond5299862008-06-11 01:31:28 +0000505 for c in '\x01\x7f\xff\x0f\xf0':
506 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000507
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000508 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
509 def test_crasher(self):
510 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000511
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()