blob: 6d2a95a8c281ce169a0e3fdc6318289472ed63ff [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
173 self.assertTrue(struct.calcsize('b')==1)
174 self.assertTrue(2 <= struct.calcsize('h'))
175 self.assertTrue(4 <= struct.calcsize('l'))
176 self.assertTrue(struct.calcsize('h') <= struct.calcsize('i'))
177 self.assertTrue(struct.calcsize('i') <= struct.calcsize('l'))
178
179 # tests for native 'q' and 'Q' when applicable
180 if HAVE_LONG_LONG:
181 self.assertEqual(struct.calcsize('q'), struct.calcsize('Q'))
182 self.assertTrue(8 <= struct.calcsize('q'))
183 self.assertTrue(struct.calcsize('l') <= struct.calcsize('q'))
184
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
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000221 self.assertTrue(expected >= 0)
222 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 Dickinsonbb3895c2009-07-07 14:15:45 +0000318 byteorders = '', '@', '=', '<', '>', '!'
319 for code in integer_codes:
320 for byteorder in byteorders:
321 if (byteorder in ('', '@') and code in ('q', 'Q') and
322 not HAVE_LONG_LONG):
323 continue
324 format = byteorder+code
325 t = IntTester(format)
326 t.run()
Benjamin Petersond5299862008-06-11 01:31:28 +0000327
328 def test_p_code(self):
329 # Test p ("Pascal string") code.
330 for code, input, expected, expectedback in [
331 ('p','abc', '\x00', ''),
332 ('1p', 'abc', '\x00', ''),
333 ('2p', 'abc', '\x01a', 'a'),
334 ('3p', 'abc', '\x02ab', 'ab'),
335 ('4p', 'abc', '\x03abc', 'abc'),
336 ('5p', 'abc', '\x03abc\x00', 'abc'),
337 ('6p', 'abc', '\x03abc\x00\x00', 'abc'),
338 ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]:
339 got = struct.pack(code, input)
340 self.assertEqual(got, expected)
341 (got,) = struct.unpack(code, got)
342 self.assertEqual(got, expectedback)
343
344 def test_705836(self):
345 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
346 # from the low-order discarded bits could propagate into the exponent
347 # field, causing the result to be wrong by a factor of 2.
348 import math
349
350 for base in range(1, 33):
351 # smaller <- largest representable float less than base.
352 delta = 0.5
353 while base - delta / 2.0 != base:
354 delta /= 2.0
355 smaller = base - delta
356 # Packing this rounds away a solid string of trailing 1 bits.
357 packed = struct.pack("<f", smaller)
358 unpacked = struct.unpack("<f", packed)[0]
359 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
360 # 16, respectively.
361 self.assertEqual(base, unpacked)
362 bigpacked = struct.pack(">f", smaller)
363 self.assertEqual(bigpacked, string_reverse(packed))
364 unpacked = struct.unpack(">f", bigpacked)[0]
365 self.assertEqual(base, unpacked)
366
367 # Largest finite IEEE single.
368 big = (1 << 24) - 1
369 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000370 packed = struct.pack(">f", big)
Benjamin Petersond5299862008-06-11 01:31:28 +0000371 unpacked = struct.unpack(">f", packed)[0]
372 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000373
Benjamin Petersond5299862008-06-11 01:31:28 +0000374 # The same, but tack on a 1 bit so it rounds up to infinity.
375 big = (1 << 25) - 1
376 big = math.ldexp(big, 127 - 24)
377 self.assertRaises(OverflowError, struct.pack, ">f", big)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000378
Mark Dickinson463dc4b2009-07-05 10:01:24 +0000379 def test_1530559(self):
Benjamin Petersond5299862008-06-11 01:31:28 +0000380 # SF bug 1530559. struct.pack raises TypeError where it used to convert.
381 for endian in ('', '>', '<'):
Mark Dickinsonbb3895c2009-07-07 14:15:45 +0000382 for fmt in integer_codes:
Benjamin Petersond5299862008-06-11 01:31:28 +0000383 self.check_float_coerce(endian + fmt, 1.0)
384 self.check_float_coerce(endian + fmt, 1.5)
Bob Ippolitoeb621272006-05-24 15:32:06 +0000385
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000386 def test_unpack_from(self, cls=str):
387 data = cls('abcd01234')
Benjamin Petersond5299862008-06-11 01:31:28 +0000388 fmt = '4s'
389 s = struct.Struct(fmt)
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000390
391 self.assertEqual(s.unpack_from(data), ('abcd',))
392 self.assertEqual(struct.unpack_from(fmt, data), ('abcd',))
393 for i in xrange(6):
394 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
395 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
396 for i in xrange(6, len(data) + 1):
397 self.assertRaises(struct.error, s.unpack_from, data, i)
398 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Martin Blais2856e5f2006-05-26 12:03:27 +0000399
Benjamin Petersond5299862008-06-11 01:31:28 +0000400 def test_pack_into(self):
401 test_string = 'Reykjavik rocks, eow!'
402 writable_buf = array.array('c', ' '*100)
403 fmt = '21s'
404 s = struct.Struct(fmt)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000405
Benjamin Petersond5299862008-06-11 01:31:28 +0000406 # Test without offset
407 s.pack_into(writable_buf, 0, test_string)
408 from_buf = writable_buf.tostring()[:len(test_string)]
409 self.assertEqual(from_buf, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000410
Benjamin Petersond5299862008-06-11 01:31:28 +0000411 # Test with offset.
412 s.pack_into(writable_buf, 10, test_string)
413 from_buf = writable_buf.tostring()[:len(test_string)+10]
414 self.assertEqual(from_buf, test_string[:10] + test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000415
Benjamin Petersond5299862008-06-11 01:31:28 +0000416 # Go beyond boundaries.
417 small_buf = array.array('c', ' '*10)
418 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
419 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Bob Ippolitoe6c9f982006-08-04 23:59:21 +0000420
Georg Brandl0638a082009-02-13 11:03:59 +0000421 # Test bogus offset (issue 3694)
422 sb = small_buf
423 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
424
Benjamin Petersond5299862008-06-11 01:31:28 +0000425 def test_pack_into_fn(self):
426 test_string = 'Reykjavik rocks, eow!'
427 writable_buf = array.array('c', ' '*100)
428 fmt = '21s'
429 pack_into = lambda *args: struct.pack_into(fmt, *args)
Martin Blais2856e5f2006-05-26 12:03:27 +0000430
Benjamin Petersond5299862008-06-11 01:31:28 +0000431 # Test without offset.
432 pack_into(writable_buf, 0, test_string)
433 from_buf = writable_buf.tostring()[:len(test_string)]
434 self.assertEqual(from_buf, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000435
Benjamin Petersond5299862008-06-11 01:31:28 +0000436 # Test with offset.
437 pack_into(writable_buf, 10, test_string)
438 from_buf = writable_buf.tostring()[:len(test_string)+10]
439 self.assertEqual(from_buf, test_string[:10] + test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000440
Benjamin Petersond5299862008-06-11 01:31:28 +0000441 # Go beyond boundaries.
442 small_buf = array.array('c', ' '*10)
443 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
444 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Martin Blais2856e5f2006-05-26 12:03:27 +0000445
Benjamin Petersond5299862008-06-11 01:31:28 +0000446 def test_unpack_with_buffer(self):
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000447 with check_py3k_warnings(("buffer.. not supported in 3.x",
448 DeprecationWarning)):
449 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
450 data1 = array.array('B', '\x12\x34\x56\x78')
451 data2 = buffer('......\x12\x34\x56\x78......', 6, 4)
452 for data in [data1, data2]:
453 value, = struct.unpack('>I', data)
454 self.assertEqual(value, 0x12345678)
455
456 self.test_unpack_from(cls=buffer)
Martin Blais2856e5f2006-05-26 12:03:27 +0000457
Benjamin Petersond5299862008-06-11 01:31:28 +0000458 def test_bool(self):
459 for prefix in tuple("<>!=")+('',):
460 false = (), [], [], '', 0
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000461 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff//2
Martin Blais2856e5f2006-05-26 12:03:27 +0000462
Benjamin Petersond5299862008-06-11 01:31:28 +0000463 falseFormat = prefix + '?' * len(false)
464 packedFalse = struct.pack(falseFormat, *false)
465 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000466
Benjamin Petersond5299862008-06-11 01:31:28 +0000467 trueFormat = prefix + '?' * len(true)
468 packedTrue = struct.pack(trueFormat, *true)
469 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000470
Benjamin Petersond5299862008-06-11 01:31:28 +0000471 self.assertEqual(len(true), len(unpackedTrue))
472 self.assertEqual(len(false), len(unpackedFalse))
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000473
Benjamin Petersond5299862008-06-11 01:31:28 +0000474 for t in unpackedFalse:
475 self.assertFalse(t)
476 for t in unpackedTrue:
477 self.assertTrue(t)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000478
Benjamin Petersond5299862008-06-11 01:31:28 +0000479 packed = struct.pack(prefix+'?', 1)
Bob Ippolito1fcdc232006-05-27 12:11:36 +0000480
Benjamin Petersond5299862008-06-11 01:31:28 +0000481 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Tim Petersfe98f962006-05-26 12:26:21 +0000482
Benjamin Petersond5299862008-06-11 01:31:28 +0000483 if len(packed) != 1:
484 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
485 %packed)
Tim Petersc65a13f2006-06-04 01:22:53 +0000486
Benjamin Petersond5299862008-06-11 01:31:28 +0000487 for c in '\x01\x7f\xff\x0f\xf0':
488 self.assertTrue(struct.unpack('>?', c)[0])
Martin v. Löwisaef4c6b2007-01-21 09:33:07 +0000489
Florent Xiclunadb4a3212010-03-20 22:21:02 +0000490 @unittest.skipUnless(IS32BIT, "Specific to 32bit machines")
491 def test_crasher(self):
492 self.assertRaises(MemoryError, struct.pack, "357913941c", "a")
Gregory P. Smith9d534572008-06-11 07:41:16 +0000493
Tim Petersf733abb2007-01-30 03:03:46 +0000494
Benjamin Petersond5299862008-06-11 01:31:28 +0000495def test_main():
Senthil Kumarance8e33a2010-01-08 19:04:16 +0000496 run_unittest(StructTest)
Tim Petersf733abb2007-01-30 03:03:46 +0000497
Benjamin Petersond5299862008-06-11 01:31:28 +0000498if __name__ == '__main__':
499 test_main()