blob: 46e777b9d1c19b75f90ba1bfc2009b46bcd31043 [file] [log] [blame]
Thomas Wouters477c8d52006-05-27 19:21:47 +00001import array
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00002import unittest
3import struct
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00004import warnings
Barry Warsaw07a0eec1996-12-12 23:34:06 +00005
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00006from functools import wraps
Brett Cannon1cd02472008-09-09 01:52:27 +00007from test.support import TestFailed, verbose, run_unittest
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00008
Tim Peters17e17d42001-06-13 22:45:27 +00009import sys
10ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +000011IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000012del sys
Tim Peters17e17d42001-06-13 22:45:27 +000013
14def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000015 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000016
17def bigendian_to_native(value):
18 if ISBIGENDIAN:
19 return value
20 else:
21 return string_reverse(value)
22
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000023class StructTest(unittest.TestCase):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000024 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000025 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000026
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000027 def test_consistence(self):
28 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000029
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000030 sz = struct.calcsize('i')
31 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000032
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000033 fmt = 'cbxxxxxxhhhhiillffd?'
34 fmt3 = '3c3b18x12h6i6l6f3d3?'
35 sz = struct.calcsize(fmt)
36 sz3 = struct.calcsize(fmt3)
37 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000038
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 self.assertRaises(struct.error, struct.pack, 'iii', 3)
40 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
41 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
42 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
43 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
44 s = struct.pack('ii', 1, 2)
45 self.assertRaises(struct.error, struct.unpack, 'iii', s)
46 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000047
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000048 def test_transitiveness(self):
49 c = b'a'
50 b = 1
51 h = 255
52 i = 65535
53 l = 65536
54 f = 3.1415
55 d = 3.1415
56 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000058 for prefix in ('', '@', '<', '>', '=', '!'):
59 for format in ('xcbhilfd?', 'xcBHILfd?'):
60 format = prefix + format
61 s = struct.pack(format, c, b, h, i, l, f, d, t)
62 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
63 self.assertEqual(cp, c)
64 self.assertEqual(bp, b)
65 self.assertEqual(hp, h)
66 self.assertEqual(ip, i)
67 self.assertEqual(lp, l)
68 self.assertEqual(int(100 * fp), int(100 * f))
69 self.assertEqual(int(100 * dp), int(100 * d))
70 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000071
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000072 def test_new_features(self):
73 # Test some of the new features in detail
74 # (format, argument, big-endian result, little-endian result, asymmetric)
75 tests = [
76 ('c', 'a', 'a', 'a', 0),
77 ('xc', 'a', '\0a', '\0a', 0),
78 ('cx', 'a', 'a\0', 'a\0', 0),
79 ('s', 'a', 'a', 'a', 0),
80 ('0s', 'helloworld', '', '', 1),
81 ('1s', 'helloworld', 'h', 'h', 1),
82 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
83 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
84 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
85 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
86 ('b', 7, '\7', '\7', 0),
87 ('b', -7, '\371', '\371', 0),
88 ('B', 7, '\7', '\7', 0),
89 ('B', 249, '\371', '\371', 0),
90 ('h', 700, '\002\274', '\274\002', 0),
91 ('h', -700, '\375D', 'D\375', 0),
92 ('H', 700, '\002\274', '\274\002', 0),
93 ('H', 0x10000-700, '\375D', 'D\375', 0),
94 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
95 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
96 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
97 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
98 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
99 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
100 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
101 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
102 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
103 ('d', 2.0, '@\000\000\000\000\000\000\000',
104 '\000\000\000\000\000\000\000@', 0),
105 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
106 ('d', -2.0, '\300\000\000\000\000\000\000\000',
107 '\000\000\000\000\000\000\000\300', 0),
108 ('?', 0, '\0', '\0', 0),
109 ('?', 3, '\1', '\1', 1),
110 ('?', True, '\1', '\1', 0),
111 ('?', [], '\0', '\0', 1),
112 ('?', (1,), '\1', '\1', 1),
113 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000114
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000115 for fmt, arg, big, lil, asy in tests:
116 big = bytes(big, "latin-1")
117 lil = bytes(lil, "latin-1")
118 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
119 ('='+fmt, ISBIGENDIAN and big or lil)]:
120 res = struct.pack(xfmt, arg)
121 self.assertEqual(res, exp)
122 self.assertEqual(struct.calcsize(xfmt), len(res))
123 rev = struct.unpack(xfmt, res)[0]
124 if isinstance(arg, str):
125 # Strings are returned as bytes since you can't know the
126 # encoding of the string when packed.
127 arg = bytes(arg, 'latin1')
128 if rev != arg:
129 self.assert_(asy)
130
131 def test_native_qQ(self):
132 # can't pack -1 as unsigned regardless
Mark Dickinson21776072009-02-10 16:13:25 +0000133 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000134 # can't pack string as 'q' regardless
135 self.assertRaises(struct.error, struct.pack, "q", "a")
136 # ditto, but 'Q'
137 self.assertRaises(struct.error, struct.pack, "Q", "a")
138
139 try:
140 struct.pack("q", 5)
141 except struct.error:
142 # does not have native q/Q
143 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000144 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000145 nbytes = struct.calcsize('q')
146 # The expected values here are in big-endian format, primarily
147 # because I'm on a little-endian machine and so this is the
148 # clearest way (for me) to force the code to get exercised.
149 for format, input, expected in (
150 ('q', -1, '\xff' * nbytes),
151 ('q', 0, '\x00' * nbytes),
152 ('Q', 0, '\x00' * nbytes),
153 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
154 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
155 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
156 expected = bytes(expected, "latin-1")
157 got = struct.pack(format, input)
158 native_expected = bigendian_to_native(expected)
159 self.assertEqual(got, native_expected)
160 retrieved = struct.unpack(format, got)[0]
161 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000162
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000163 def test_standard_integers(self):
164 # Standard integer tests (bBhHiIlLqQ).
165 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000166
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000167 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000168
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000169 def __init__(self, formatpair, bytesize):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000170 super(IntTester, self).__init__(methodName='test_one')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000171 self.assertEqual(len(formatpair), 2)
172 self.formatpair = formatpair
173 for direction in "<>!=":
174 for code in formatpair:
175 format = direction + code
176 self.assertEqual(struct.calcsize(format), bytesize)
177 self.bytesize = bytesize
178 self.bitsize = bytesize * 8
179 self.signed_code, self.unsigned_code = formatpair
180 self.unsigned_min = 0
181 self.unsigned_max = 2**self.bitsize - 1
182 self.signed_min = -(2**(self.bitsize-1))
183 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000184
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000185 def test_one(self, x, pack=struct.pack,
186 unpack=struct.unpack,
187 unhexlify=binascii.unhexlify):
188 # Try signed.
189 code = self.signed_code
190 if self.signed_min <= x <= self.signed_max:
191 # Try big-endian.
192 expected = x
193 if x < 0:
194 expected += 1 << self.bitsize
195 self.assert_(expected > 0)
196 expected = hex(expected)[2:] # chop "0x"
197 if len(expected) & 1:
198 expected = "0" + expected
199 expected = unhexlify(expected)
200 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000201
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000202 # Pack work?
203 format = ">" + code
204 got = pack(format, x)
205 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000206
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000207 # Unpack work?
208 retrieved = unpack(format, got)[0]
209 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000210
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000211 # Adding any byte should cause a "too big" error.
212 self.assertRaises((struct.error, TypeError),
213 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000214
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000215 # Try little-endian.
216 format = "<" + code
217 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000218
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000219 # Pack work?
220 got = pack(format, x)
221 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000222
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000223 # Unpack work?
224 retrieved = unpack(format, got)[0]
225 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000226
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000227 # Adding any byte should cause a "too big" error.
228 self.assertRaises((struct.error, TypeError),
229 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000230
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000231 else:
232 # x is out of range -- verify pack realizes that.
Mark Dickinsonea835e72009-04-19 20:40:33 +0000233 self.assertRaises(struct.error, pack, ">" + code, x)
234 self.assertRaises(struct.error, pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000235
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000236 # Much the same for unsigned.
237 code = self.unsigned_code
238 if self.unsigned_min <= x <= self.unsigned_max:
239 # Try big-endian.
240 format = ">" + code
241 expected = x
242 expected = hex(expected)[2:] # chop "0x"
243 if len(expected) & 1:
244 expected = "0" + expected
245 expected = unhexlify(expected)
246 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000247
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000248 # Pack work?
249 got = pack(format, x)
250 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000251
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000252 # Unpack work?
253 retrieved = unpack(format, got)[0]
254 self.assertEqual(x, retrieved)
255
256 # Adding any byte should cause a "too big" error.
257 self.assertRaises((struct.error, TypeError),
258 unpack, format, b'\x01' + got)
259
260 # Try little-endian.
261 format = "<" + code
262 expected = string_reverse(expected)
263
264 # Pack work?
265 got = pack(format, x)
266 self.assertEqual(got, expected)
267
268 # Unpack work?
269 retrieved = unpack(format, got)[0]
270 self.assertEqual(x, retrieved)
271
272 # Adding any byte should cause a "too big" error.
273 self.assertRaises((struct.error, TypeError),
274 unpack, format, b'\x01' + got)
275
276 else:
277 # x is out of range -- verify pack realizes that.
Mark Dickinsonea835e72009-04-19 20:40:33 +0000278 self.assertRaises(struct.error, pack, ">" + code, x)
279 self.assertRaises(struct.error, pack, "<" + code, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000280
281 def run(self):
282 from random import randrange
283
284 # Create all interesting powers of 2.
285 values = []
286 for exp in range(self.bitsize + 3):
287 values.append(1 << exp)
288
289 # Add some random values.
290 for i in range(self.bitsize):
291 val = 0
292 for j in range(self.bytesize):
293 val = (val << 8) | randrange(256)
294 values.append(val)
295
296 # Try all those, and their negations, and +-1 from them. Note
297 # that this tests all power-of-2 boundaries in range, and a few out
298 # of range, plus +-(2**n +- 1).
299 for base in values:
300 for val in -base, base:
301 for incr in -1, 0, 1:
302 x = val + incr
303 try:
304 x = int(x)
305 except OverflowError:
306 pass
307 self.test_one(x)
308
309 # Some error cases.
310 for direction in "<>":
311 for code in self.formatpair:
Mark Dickinsonea835e72009-04-19 20:40:33 +0000312 for badobject in "a string", 3+42j, randrange, -1729.0:
313 self.assertRaises(struct.error,
314 struct.pack, direction + code,
315 badobject)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000316
317 for args in [("bB", 1),
318 ("hH", 2),
319 ("iI", 4),
320 ("lL", 4),
321 ("qQ", 8)]:
322 t = IntTester(*args)
323 t.run()
324
325 def test_p_code(self):
326 # Test p ("Pascal string") code.
327 for code, input, expected, expectedback in [
328 ('p','abc', '\x00', b''),
329 ('1p', 'abc', '\x00', b''),
330 ('2p', 'abc', '\x01a', b'a'),
331 ('3p', 'abc', '\x02ab', b'ab'),
332 ('4p', 'abc', '\x03abc', b'abc'),
333 ('5p', 'abc', '\x03abc\x00', b'abc'),
334 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
335 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
336 expected = bytes(expected, "latin-1")
337 got = struct.pack(code, input)
338 self.assertEqual(got, expected)
339 (got,) = struct.unpack(code, got)
340 self.assertEqual(got, expectedback)
341
342 def test_705836(self):
343 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
344 # from the low-order discarded bits could propagate into the exponent
345 # field, causing the result to be wrong by a factor of 2.
346 import math
347
348 for base in range(1, 33):
349 # smaller <- largest representable float less than base.
350 delta = 0.5
351 while base - delta / 2.0 != base:
352 delta /= 2.0
353 smaller = base - delta
354 # Packing this rounds away a solid string of trailing 1 bits.
355 packed = struct.pack("<f", smaller)
356 unpacked = struct.unpack("<f", packed)[0]
357 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
358 # 16, respectively.
359 self.assertEqual(base, unpacked)
360 bigpacked = struct.pack(">f", smaller)
361 self.assertEqual(bigpacked, string_reverse(packed))
362 unpacked = struct.unpack(">f", bigpacked)[0]
363 self.assertEqual(base, unpacked)
364
365 # Largest finite IEEE single.
366 big = (1 << 24) - 1
367 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000368 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000369 unpacked = struct.unpack(">f", packed)[0]
370 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000371
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000372 # The same, but tack on a 1 bit so it rounds up to infinity.
373 big = (1 << 25) - 1
374 big = math.ldexp(big, 127 - 24)
375 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000376
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000377 def test_1229380(self):
378 # SF bug 1229380. No struct.pack exception for some out of
379 # range integers
380 import sys
381 for endian in ('', '>', '<'):
382 for fmt in ('B', 'H', 'I', 'L'):
383 self.assertRaises((struct.error, OverflowError), struct.pack,
384 endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000385
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000386 self.assertRaises((struct.error, OverflowError), struct.pack,
387 endian + 'B', 300)
388 self.assertRaises((struct.error, OverflowError), struct.pack,
389 endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000390
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000391 self.assertRaises((struct.error, OverflowError), struct.pack,
392 endian + 'I', sys.maxsize * 4)
393 self.assertRaises((struct.error, OverflowError), struct.pack,
394 endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000395
Mark Dickinsonea835e72009-04-19 20:40:33 +0000396 def test_1530559(self):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000397 for endian in ('', '>', '<'):
Mark Dickinsonea835e72009-04-19 20:40:33 +0000398 for fmt in ('B', 'H', 'I', 'L', 'Q', 'b', 'h', 'i', 'l', 'q'):
399 self.assertRaises(struct.error, struct.pack, endian + fmt, 1.0)
400 self.assertRaises(struct.error, struct.pack, endian + fmt, 1.5)
401 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
402 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
403
Thomas Wouters477c8d52006-05-27 19:21:47 +0000404
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000405 def test_unpack_from(self):
406 test_string = b'abcd01234'
407 fmt = '4s'
408 s = struct.Struct(fmt)
409 for cls in (bytes, bytearray):
410 data = cls(test_string)
411 if not isinstance(data, (bytes, bytearray)):
412 bytes_data = bytes(data, 'latin1')
413 else:
414 bytes_data = data
415 self.assertEqual(s.unpack_from(data), (b'abcd',))
416 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
417 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
418 for i in range(6):
419 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
420 for i in range(6, len(test_string) + 1):
421 self.assertRaises(struct.error, s.unpack_from, data, i)
422 for cls in (bytes, bytearray):
423 data = cls(test_string)
424 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
425 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
426 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
427 for i in range(6):
428 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
429 for i in range(6, len(test_string) + 1):
430 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000431
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000432 def test_pack_into(self):
433 test_string = b'Reykjavik rocks, eow!'
434 writable_buf = array.array('b', b' '*100)
435 fmt = '21s'
436 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000437
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000438 # Test without offset
439 s.pack_into(writable_buf, 0, test_string)
440 from_buf = writable_buf.tostring()[:len(test_string)]
441 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000442
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000443 # Test with offset.
444 s.pack_into(writable_buf, 10, test_string)
445 from_buf = writable_buf.tostring()[:len(test_string)+10]
446 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 # Go beyond boundaries.
449 small_buf = array.array('b', b' '*10)
450 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
451 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000452
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000453 # Test bogus offset (issue 3694)
454 sb = small_buf
455 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
456
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000457 def test_pack_into_fn(self):
458 test_string = b'Reykjavik rocks, eow!'
459 writable_buf = array.array('b', b' '*100)
460 fmt = '21s'
461 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000463 # Test without offset.
464 pack_into(writable_buf, 0, test_string)
465 from_buf = writable_buf.tostring()[:len(test_string)]
466 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000467
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000468 # Test with offset.
469 pack_into(writable_buf, 10, test_string)
470 from_buf = writable_buf.tostring()[:len(test_string)+10]
471 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000472
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000473 # Go beyond boundaries.
474 small_buf = array.array('b', b' '*10)
475 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
476 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000477
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000478 def test_unpack_with_buffer(self):
479 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
480 data1 = array.array('B', b'\x12\x34\x56\x78')
481 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
482 for data in [data1, data2]:
483 value, = struct.unpack('>I', data)
484 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000485
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000486 def test_bool(self):
487 for prefix in tuple("<>!=")+('',):
488 false = (), [], [], '', 0
489 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000490
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000491 falseFormat = prefix + '?' * len(false)
492 packedFalse = struct.pack(falseFormat, *false)
493 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000494
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000495 trueFormat = prefix + '?' * len(true)
496 packedTrue = struct.pack(trueFormat, *true)
497 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000498
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000499 self.assertEqual(len(true), len(unpackedTrue))
500 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 for t in unpackedFalse:
503 self.assertFalse(t)
504 for t in unpackedTrue:
505 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000508
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000509 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000510
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000511 if len(packed) != 1:
512 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
513 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000514
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000515 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
516 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000517
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000518 if IS32BIT:
519 def test_crasher(self):
520 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
521
522
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000523def test_main():
524 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000525
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000526if __name__ == '__main__':
527 test_main()