blob: 9ed3220e8b7f867b196611082c9aff879490ce81 [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
Tim Peters17e17d42001-06-13 22:45:27 +00004import sys
Mark Dickinson94820322010-03-05 14:45:49 +00005
6from test.support import run_unittest
7
Tim Peters17e17d42001-06-13 22:45:27 +00008ISBIGENDIAN = sys.byteorder == "big"
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00009IS32BIT = sys.maxsize == 0x7fffffff
Tim Peters17e17d42001-06-13 22:45:27 +000010
11def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000012 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000013
14def bigendian_to_native(value):
15 if ISBIGENDIAN:
16 return value
17 else:
18 return string_reverse(value)
19
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000020class StructTest(unittest.TestCase):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000021 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000022 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000023
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000024 def test_consistence(self):
25 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000026
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000027 sz = struct.calcsize('i')
28 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000029
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000030 fmt = 'cbxxxxxxhhhhiillffd?'
31 fmt3 = '3c3b18x12h6i6l6f3d3?'
32 sz = struct.calcsize(fmt)
33 sz3 = struct.calcsize(fmt3)
34 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000035
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000036 self.assertRaises(struct.error, struct.pack, 'iii', 3)
37 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
38 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
39 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
40 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
41 s = struct.pack('ii', 1, 2)
42 self.assertRaises(struct.error, struct.unpack, 'iii', s)
43 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000044
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000045 def test_transitiveness(self):
46 c = b'a'
47 b = 1
48 h = 255
49 i = 65535
50 l = 65536
51 f = 3.1415
52 d = 3.1415
53 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000054
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000055 for prefix in ('', '@', '<', '>', '=', '!'):
56 for format in ('xcbhilfd?', 'xcBHILfd?'):
57 format = prefix + format
58 s = struct.pack(format, c, b, h, i, l, f, d, t)
59 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
60 self.assertEqual(cp, c)
61 self.assertEqual(bp, b)
62 self.assertEqual(hp, h)
63 self.assertEqual(ip, i)
64 self.assertEqual(lp, l)
65 self.assertEqual(int(100 * fp), int(100 * f))
66 self.assertEqual(int(100 * dp), int(100 * d))
67 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000068
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000069 def test_new_features(self):
70 # Test some of the new features in detail
71 # (format, argument, big-endian result, little-endian result, asymmetric)
72 tests = [
73 ('c', 'a', 'a', 'a', 0),
74 ('xc', 'a', '\0a', '\0a', 0),
75 ('cx', 'a', 'a\0', 'a\0', 0),
76 ('s', 'a', 'a', 'a', 0),
77 ('0s', 'helloworld', '', '', 1),
78 ('1s', 'helloworld', 'h', 'h', 1),
79 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
80 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
81 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
82 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
83 ('b', 7, '\7', '\7', 0),
84 ('b', -7, '\371', '\371', 0),
85 ('B', 7, '\7', '\7', 0),
86 ('B', 249, '\371', '\371', 0),
87 ('h', 700, '\002\274', '\274\002', 0),
88 ('h', -700, '\375D', 'D\375', 0),
89 ('H', 700, '\002\274', '\274\002', 0),
90 ('H', 0x10000-700, '\375D', 'D\375', 0),
91 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
92 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
93 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
94 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
95 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
96 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
97 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
98 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
99 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
100 ('d', 2.0, '@\000\000\000\000\000\000\000',
101 '\000\000\000\000\000\000\000@', 0),
102 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
103 ('d', -2.0, '\300\000\000\000\000\000\000\000',
104 '\000\000\000\000\000\000\000\300', 0),
105 ('?', 0, '\0', '\0', 0),
106 ('?', 3, '\1', '\1', 1),
107 ('?', True, '\1', '\1', 0),
108 ('?', [], '\0', '\0', 1),
109 ('?', (1,), '\1', '\1', 1),
110 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000111
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000112 for fmt, arg, big, lil, asy in tests:
113 big = bytes(big, "latin-1")
114 lil = bytes(lil, "latin-1")
115 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
116 ('='+fmt, ISBIGENDIAN and big or lil)]:
117 res = struct.pack(xfmt, arg)
118 self.assertEqual(res, exp)
119 self.assertEqual(struct.calcsize(xfmt), len(res))
120 rev = struct.unpack(xfmt, res)[0]
121 if isinstance(arg, str):
122 # Strings are returned as bytes since you can't know the
123 # encoding of the string when packed.
124 arg = bytes(arg, 'latin1')
125 if rev != arg:
Georg Brandlab91fde2009-08-13 08:51:18 +0000126 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000127
128 def test_native_qQ(self):
129 # can't pack -1 as unsigned regardless
Mark Dickinson21776072009-02-10 16:13:25 +0000130 self.assertRaises((struct.error, OverflowError), struct.pack, "Q", -1)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000131 # can't pack string as 'q' regardless
132 self.assertRaises(struct.error, struct.pack, "q", "a")
133 # ditto, but 'Q'
134 self.assertRaises(struct.error, struct.pack, "Q", "a")
135
136 try:
137 struct.pack("q", 5)
138 except struct.error:
139 # does not have native q/Q
140 pass
Tim Peters17e17d42001-06-13 22:45:27 +0000141 else:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000142 nbytes = struct.calcsize('q')
143 # The expected values here are in big-endian format, primarily
144 # because I'm on a little-endian machine and so this is the
145 # clearest way (for me) to force the code to get exercised.
146 for format, input, expected in (
147 ('q', -1, '\xff' * nbytes),
148 ('q', 0, '\x00' * nbytes),
149 ('Q', 0, '\x00' * nbytes),
150 ('q', 1, '\x00' * (nbytes-1) + '\x01'),
151 ('Q', (1 << (8*nbytes))-1, '\xff' * nbytes),
152 ('q', (1 << (8*nbytes-1))-1, '\x7f' + '\xff' * (nbytes - 1))):
153 expected = bytes(expected, "latin-1")
154 got = struct.pack(format, input)
155 native_expected = bigendian_to_native(expected)
156 self.assertEqual(got, native_expected)
157 retrieved = struct.unpack(format, got)[0]
158 self.assertEqual(retrieved, input)
Tim Peters7a3bfc32001-06-12 01:22:22 +0000159
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000160 def test_standard_integers(self):
161 # Standard integer tests (bBhHiIlLqQ).
162 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000163
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000164 class IntTester(unittest.TestCase):
Tim Peters17e17d42001-06-13 22:45:27 +0000165
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000166 def __init__(self, formatpair, bytesize):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000167 super(IntTester, self).__init__(methodName='test_one')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000168 self.assertEqual(len(formatpair), 2)
169 self.formatpair = formatpair
170 for direction in "<>!=":
171 for code in formatpair:
172 format = direction + code
173 self.assertEqual(struct.calcsize(format), bytesize)
174 self.bytesize = bytesize
175 self.bitsize = bytesize * 8
176 self.signed_code, self.unsigned_code = formatpair
177 self.unsigned_min = 0
178 self.unsigned_max = 2**self.bitsize - 1
179 self.signed_min = -(2**(self.bitsize-1))
180 self.signed_max = 2**(self.bitsize-1) - 1
Tim Peters17e17d42001-06-13 22:45:27 +0000181
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000182 def test_one(self, x, pack=struct.pack,
183 unpack=struct.unpack,
184 unhexlify=binascii.unhexlify):
185 # Try signed.
186 code = self.signed_code
187 if self.signed_min <= x <= self.signed_max:
188 # Try big-endian.
189 expected = x
190 if x < 0:
191 expected += 1 << self.bitsize
Georg Brandlab91fde2009-08-13 08:51:18 +0000192 self.assertTrue(expected > 0)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000193 expected = hex(expected)[2:] # chop "0x"
194 if len(expected) & 1:
195 expected = "0" + expected
196 expected = unhexlify(expected)
197 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Peters17e17d42001-06-13 22:45:27 +0000198
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000199 # Pack work?
200 format = ">" + code
201 got = pack(format, x)
202 self.assertEqual(got, expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000203
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000204 # Unpack work?
205 retrieved = unpack(format, got)[0]
206 self.assertEqual(x, retrieved)
Tim Peters0891ac02001-09-15 02:35:15 +0000207
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000208 # Adding any byte should cause a "too big" error.
209 self.assertRaises((struct.error, TypeError),
210 unpack, format, b'\x01' + got)
Tim Peters0891ac02001-09-15 02:35:15 +0000211
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000212 # Try little-endian.
213 format = "<" + code
214 expected = string_reverse(expected)
Tim Peters0891ac02001-09-15 02:35:15 +0000215
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000216 # Pack work?
217 got = pack(format, x)
218 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000219
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000220 # Unpack work?
221 retrieved = unpack(format, got)[0]
222 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 # Adding any byte should cause a "too big" error.
225 self.assertRaises((struct.error, TypeError),
226 unpack, format, b'\x01' + got)
Tim Petersd50ade62003-03-20 18:32:13 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 else:
229 # x is out of range -- verify pack realizes that.
Mark Dickinsonea835e72009-04-19 20:40:33 +0000230 self.assertRaises(struct.error, pack, ">" + code, x)
231 self.assertRaises(struct.error, pack, "<" + code, x)
Tim Petersd50ade62003-03-20 18:32:13 +0000232
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000233 # Much the same for unsigned.
234 code = self.unsigned_code
235 if self.unsigned_min <= x <= self.unsigned_max:
236 # Try big-endian.
237 format = ">" + code
238 expected = x
239 expected = hex(expected)[2:] # chop "0x"
240 if len(expected) & 1:
241 expected = "0" + expected
242 expected = unhexlify(expected)
243 expected = b"\x00" * (self.bytesize - len(expected)) + expected
Tim Petersd50ade62003-03-20 18:32:13 +0000244
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000245 # Pack work?
246 got = pack(format, x)
247 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000248
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000249 # Unpack work?
250 retrieved = unpack(format, got)[0]
251 self.assertEqual(x, retrieved)
252
253 # Adding any byte should cause a "too big" error.
254 self.assertRaises((struct.error, TypeError),
255 unpack, format, b'\x01' + got)
256
257 # Try little-endian.
258 format = "<" + code
259 expected = string_reverse(expected)
260
261 # Pack work?
262 got = pack(format, x)
263 self.assertEqual(got, expected)
264
265 # Unpack work?
266 retrieved = unpack(format, got)[0]
267 self.assertEqual(x, retrieved)
268
269 # Adding any byte should cause a "too big" error.
270 self.assertRaises((struct.error, TypeError),
271 unpack, format, b'\x01' + got)
272
273 else:
274 # x is out of range -- verify pack realizes that.
Mark Dickinsonea835e72009-04-19 20:40:33 +0000275 self.assertRaises(struct.error, pack, ">" + code, x)
276 self.assertRaises(struct.error, pack, "<" + code, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000277
278 def run(self):
279 from random import randrange
280
281 # Create all interesting powers of 2.
282 values = []
283 for exp in range(self.bitsize + 3):
284 values.append(1 << exp)
285
286 # Add some random values.
287 for i in range(self.bitsize):
288 val = 0
289 for j in range(self.bytesize):
290 val = (val << 8) | randrange(256)
291 values.append(val)
292
293 # Try all those, and their negations, and +-1 from them. Note
294 # that this tests all power-of-2 boundaries in range, and a few out
295 # of range, plus +-(2**n +- 1).
296 for base in values:
297 for val in -base, base:
298 for incr in -1, 0, 1:
299 x = val + incr
300 try:
301 x = int(x)
302 except OverflowError:
303 pass
304 self.test_one(x)
305
306 # Some error cases.
307 for direction in "<>":
308 for code in self.formatpair:
Mark Dickinsonea835e72009-04-19 20:40:33 +0000309 for badobject in "a string", 3+42j, randrange, -1729.0:
310 self.assertRaises(struct.error,
311 struct.pack, direction + code,
312 badobject)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000313
314 for args in [("bB", 1),
315 ("hH", 2),
316 ("iI", 4),
317 ("lL", 4),
318 ("qQ", 8)]:
319 t = IntTester(*args)
320 t.run()
321
322 def test_p_code(self):
323 # Test p ("Pascal string") code.
324 for code, input, expected, expectedback in [
325 ('p','abc', '\x00', b''),
326 ('1p', 'abc', '\x00', b''),
327 ('2p', 'abc', '\x01a', b'a'),
328 ('3p', 'abc', '\x02ab', b'ab'),
329 ('4p', 'abc', '\x03abc', b'abc'),
330 ('5p', 'abc', '\x03abc\x00', b'abc'),
331 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
332 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
333 expected = bytes(expected, "latin-1")
334 got = struct.pack(code, input)
335 self.assertEqual(got, expected)
336 (got,) = struct.unpack(code, got)
337 self.assertEqual(got, expectedback)
338
339 def test_705836(self):
340 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
341 # from the low-order discarded bits could propagate into the exponent
342 # field, causing the result to be wrong by a factor of 2.
343 import math
344
345 for base in range(1, 33):
346 # smaller <- largest representable float less than base.
347 delta = 0.5
348 while base - delta / 2.0 != base:
349 delta /= 2.0
350 smaller = base - delta
351 # Packing this rounds away a solid string of trailing 1 bits.
352 packed = struct.pack("<f", smaller)
353 unpacked = struct.unpack("<f", packed)[0]
354 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
355 # 16, respectively.
356 self.assertEqual(base, unpacked)
357 bigpacked = struct.pack(">f", smaller)
358 self.assertEqual(bigpacked, string_reverse(packed))
359 unpacked = struct.unpack(">f", bigpacked)[0]
360 self.assertEqual(base, unpacked)
361
362 # Largest finite IEEE single.
363 big = (1 << 24) - 1
364 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000365 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000366 unpacked = struct.unpack(">f", packed)[0]
367 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000368
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000369 # The same, but tack on a 1 bit so it rounds up to infinity.
370 big = (1 << 25) - 1
371 big = math.ldexp(big, 127 - 24)
372 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000373
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000374 def test_1229380(self):
375 # SF bug 1229380. No struct.pack exception for some out of
376 # range integers
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000377 for endian in ('', '>', '<'):
378 for fmt in ('B', 'H', 'I', 'L'):
379 self.assertRaises((struct.error, OverflowError), struct.pack,
380 endian + fmt, -1)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000381
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000382 self.assertRaises((struct.error, OverflowError), struct.pack,
383 endian + 'B', 300)
384 self.assertRaises((struct.error, OverflowError), struct.pack,
385 endian + 'H', 70000)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000386
Mark Dickinsonb40b9472009-03-29 16:58:21 +0000387 self.assertRaises((struct.error, OverflowError), struct.pack,
388 endian + 'I', sys.maxsize * 4)
389 self.assertRaises((struct.error, OverflowError), struct.pack,
390 endian + 'L', sys.maxsize * 4)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000391
Mark Dickinsonea835e72009-04-19 20:40:33 +0000392 def test_1530559(self):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000393 for endian in ('', '>', '<'):
Mark Dickinsonea835e72009-04-19 20:40:33 +0000394 for fmt in ('B', 'H', 'I', 'L', 'Q', 'b', 'h', 'i', 'l', 'q'):
395 self.assertRaises(struct.error, struct.pack, endian + fmt, 1.0)
396 self.assertRaises(struct.error, struct.pack, endian + fmt, 1.5)
397 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
398 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
399
Thomas Wouters477c8d52006-05-27 19:21:47 +0000400
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000401 def test_unpack_from(self):
402 test_string = b'abcd01234'
403 fmt = '4s'
404 s = struct.Struct(fmt)
405 for cls in (bytes, bytearray):
406 data = cls(test_string)
407 if not isinstance(data, (bytes, bytearray)):
408 bytes_data = bytes(data, 'latin1')
409 else:
410 bytes_data = data
411 self.assertEqual(s.unpack_from(data), (b'abcd',))
412 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
413 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
414 for i in range(6):
415 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
416 for i in range(6, len(test_string) + 1):
417 self.assertRaises(struct.error, s.unpack_from, data, i)
418 for cls in (bytes, bytearray):
419 data = cls(test_string)
420 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
421 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
422 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
423 for i in range(6):
424 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
425 for i in range(6, len(test_string) + 1):
426 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000427
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000428 def test_pack_into(self):
429 test_string = b'Reykjavik rocks, eow!'
430 writable_buf = array.array('b', b' '*100)
431 fmt = '21s'
432 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000433
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000434 # Test without offset
435 s.pack_into(writable_buf, 0, test_string)
436 from_buf = writable_buf.tostring()[:len(test_string)]
437 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000438
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000439 # Test with offset.
440 s.pack_into(writable_buf, 10, test_string)
441 from_buf = writable_buf.tostring()[:len(test_string)+10]
442 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000443
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000444 # Go beyond boundaries.
445 small_buf = array.array('b', b' '*10)
Benjamin Peterson003f5232010-07-07 22:50:58 +0000446 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
447 test_string)
448 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
449 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000450
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000451 # Test bogus offset (issue 3694)
452 sb = small_buf
453 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
454
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000455 def test_pack_into_fn(self):
456 test_string = b'Reykjavik rocks, eow!'
457 writable_buf = array.array('b', b' '*100)
458 fmt = '21s'
459 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 # Test without offset.
462 pack_into(writable_buf, 0, test_string)
463 from_buf = writable_buf.tostring()[:len(test_string)]
464 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000465
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000466 # Test with offset.
467 pack_into(writable_buf, 10, test_string)
468 from_buf = writable_buf.tostring()[:len(test_string)+10]
469 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000470
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000471 # Go beyond boundaries.
472 small_buf = array.array('b', b' '*10)
Benjamin Peterson003f5232010-07-07 22:50:58 +0000473 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
474 test_string)
475 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
476 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):
Ezio Melotti13925002011-03-16 11:05:33 +0200479 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000480 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):
Benjamin Petersonf092c7c2010-07-07 22:46:00 +0000487 class ExplodingBool(object):
488 def __bool__(self):
489 raise IOError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000490 for prefix in tuple("<>!=")+('',):
491 false = (), [], [], '', 0
492 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000493
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000494 falseFormat = prefix + '?' * len(false)
495 packedFalse = struct.pack(falseFormat, *false)
496 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000497
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000498 trueFormat = prefix + '?' * len(true)
499 packedTrue = struct.pack(trueFormat, *true)
500 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000501
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000502 self.assertEqual(len(true), len(unpackedTrue))
503 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 for t in unpackedFalse:
506 self.assertFalse(t)
507 for t in unpackedTrue:
508 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000509
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000510 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000511
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000512 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000513
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000514 if len(packed) != 1:
515 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
516 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000517
Benjamin Petersonf092c7c2010-07-07 22:46:00 +0000518 self.assertRaises(IOError, struct.pack, prefix + '?',
519 ExplodingBool())
520
521 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
522 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000523
Mark Dickinson4a3acca2010-06-11 20:08:36 +0000524 def test_count_overflow(self):
525 hugecount = '{}b'.format(sys.maxsize+1)
526 self.assertRaises(struct.error, struct.calcsize, hugecount)
527
528 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
529 self.assertRaises(struct.error, struct.calcsize, hugecount2)
530
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000531 if IS32BIT:
532 def test_crasher(self):
533 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
534
535
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000536def test_main():
537 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000538
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000539if __name__ == '__main__':
540 test_main()