blob: 2222562a5d38ec3053fe2f632f133a9839ba1480 [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 Dickinson79d38ac2010-03-05 14:44:08 +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
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000011integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'
12byteorders = '', '@', '=', '<', '>', '!'
13
14# Native 'q' packing isn't available on systems that don't have the C
15# long long type.
16try:
17 struct.pack('q', 5)
18except struct.error:
19 HAVE_LONG_LONG = False
20else:
21 HAVE_LONG_LONG = True
22
Tim Peters17e17d42001-06-13 22:45:27 +000023def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000024 return s[::-1]
Tim Peters17e17d42001-06-13 22:45:27 +000025
26def bigendian_to_native(value):
27 if ISBIGENDIAN:
28 return value
29 else:
30 return string_reverse(value)
31
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000032class StructTest(unittest.TestCase):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000033 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000034 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000035
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000036 def test_consistence(self):
37 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000038
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000039 sz = struct.calcsize('i')
40 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000041
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000042 fmt = 'cbxxxxxxhhhhiillffd?'
43 fmt3 = '3c3b18x12h6i6l6f3d3?'
44 sz = struct.calcsize(fmt)
45 sz3 = struct.calcsize(fmt3)
46 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000047
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000048 self.assertRaises(struct.error, struct.pack, 'iii', 3)
49 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
50 self.assertRaises(struct.error, struct.pack, 'i', 'foo')
51 self.assertRaises(struct.error, struct.pack, 'P', 'foo')
52 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
53 s = struct.pack('ii', 1, 2)
54 self.assertRaises(struct.error, struct.unpack, 'iii', s)
55 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000056
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000057 def test_transitiveness(self):
58 c = b'a'
59 b = 1
60 h = 255
61 i = 65535
62 l = 65536
63 f = 3.1415
64 d = 3.1415
65 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000066
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000067 for prefix in ('', '@', '<', '>', '=', '!'):
68 for format in ('xcbhilfd?', 'xcBHILfd?'):
69 format = prefix + format
70 s = struct.pack(format, c, b, h, i, l, f, d, t)
71 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
72 self.assertEqual(cp, c)
73 self.assertEqual(bp, b)
74 self.assertEqual(hp, h)
75 self.assertEqual(ip, i)
76 self.assertEqual(lp, l)
77 self.assertEqual(int(100 * fp), int(100 * f))
78 self.assertEqual(int(100 * dp), int(100 * d))
79 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000080
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000081 def test_new_features(self):
82 # Test some of the new features in detail
83 # (format, argument, big-endian result, little-endian result, asymmetric)
84 tests = [
85 ('c', 'a', 'a', 'a', 0),
86 ('xc', 'a', '\0a', '\0a', 0),
87 ('cx', 'a', 'a\0', 'a\0', 0),
88 ('s', 'a', 'a', 'a', 0),
89 ('0s', 'helloworld', '', '', 1),
90 ('1s', 'helloworld', 'h', 'h', 1),
91 ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
92 ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
93 ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
94 ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
95 ('b', 7, '\7', '\7', 0),
96 ('b', -7, '\371', '\371', 0),
97 ('B', 7, '\7', '\7', 0),
98 ('B', 249, '\371', '\371', 0),
99 ('h', 700, '\002\274', '\274\002', 0),
100 ('h', -700, '\375D', 'D\375', 0),
101 ('H', 700, '\002\274', '\274\002', 0),
102 ('H', 0x10000-700, '\375D', 'D\375', 0),
103 ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
104 ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
105 ('I', 70000000, '\004,\035\200', '\200\035,\004', 0),
106 ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
107 ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
108 ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
109 ('L', 70000000, '\004,\035\200', '\200\035,\004', 0),
110 ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0),
111 ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
112 ('d', 2.0, '@\000\000\000\000\000\000\000',
113 '\000\000\000\000\000\000\000@', 0),
114 ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
115 ('d', -2.0, '\300\000\000\000\000\000\000\000',
116 '\000\000\000\000\000\000\000\300', 0),
117 ('?', 0, '\0', '\0', 0),
118 ('?', 3, '\1', '\1', 1),
119 ('?', True, '\1', '\1', 0),
120 ('?', [], '\0', '\0', 1),
121 ('?', (1,), '\1', '\1', 1),
122 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000123
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000124 for fmt, arg, big, lil, asy in tests:
125 big = bytes(big, "latin-1")
126 lil = bytes(lil, "latin-1")
127 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
128 ('='+fmt, ISBIGENDIAN and big or lil)]:
129 res = struct.pack(xfmt, arg)
130 self.assertEqual(res, exp)
131 self.assertEqual(struct.calcsize(xfmt), len(res))
132 rev = struct.unpack(xfmt, res)[0]
133 if isinstance(arg, str):
134 # Strings are returned as bytes since you can't know the
135 # encoding of the string when packed.
136 arg = bytes(arg, 'latin1')
137 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000138 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000139
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000140 def test_calcsize(self):
141 expected_size = {
142 'b': 1, 'B': 1,
143 'h': 2, 'H': 2,
144 'i': 4, 'I': 4,
145 'l': 4, 'L': 4,
146 'q': 8, 'Q': 8,
147 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000148
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000149 # standard integer sizes
150 for code in integer_codes:
151 for byteorder in '=', '<', '>', '!':
152 format = byteorder+code
153 size = struct.calcsize(format)
154 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000155
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000156 # native integer sizes
157 native_pairs = 'bB', 'hH', 'iI', 'lL'
158 if HAVE_LONG_LONG:
159 native_pairs += 'qQ',
160 for format_pair in native_pairs:
161 for byteorder in '', '@':
162 signed_size = struct.calcsize(byteorder + format_pair[0])
163 unsigned_size = struct.calcsize(byteorder + format_pair[1])
164 self.assertEqual(signed_size, unsigned_size)
165
166 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000167 self.assertEqual(struct.calcsize('b'), 1)
168 self.assertLessEqual(2, struct.calcsize('h'))
169 self.assertLessEqual(4, struct.calcsize('l'))
170 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
171 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000172 if HAVE_LONG_LONG:
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000173 self.assertLessEqual(8, struct.calcsize('q'))
174 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000175
176 def test_integers(self):
177 # Integer tests (bBhHiIlLqQ).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000178 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000179
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000180 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000181 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000182 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000183 self.format = format
184 self.code = format[-1]
185 self.byteorder = format[:-1]
186 if not self.byteorder in byteorders:
187 raise ValueError("unrecognized packing byteorder: %s" %
188 self.byteorder)
189 self.bytesize = struct.calcsize(format)
190 self.bitsize = self.bytesize * 8
191 if self.code in tuple('bhilq'):
192 self.signed = True
193 self.min_value = -(2**(self.bitsize-1))
194 self.max_value = 2**(self.bitsize-1) - 1
195 elif self.code in tuple('BHILQ'):
196 self.signed = False
197 self.min_value = 0
198 self.max_value = 2**self.bitsize - 1
199 else:
200 raise ValueError("unrecognized format code: %s" %
201 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000202
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000203 def test_one(self, x, pack=struct.pack,
204 unpack=struct.unpack,
205 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000206
207 format = self.format
208 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000209 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000210 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000211 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000212 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000213 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000214 if len(expected) & 1:
215 expected = "0" + expected
216 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000217 expected = (b"\x00" * (self.bytesize - len(expected)) +
218 expected)
219 if (self.byteorder == '<' or
220 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
221 expected = string_reverse(expected)
222 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000223
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000224 # Pack work?
225 got = pack(format, x)
226 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000227
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000228 # Unpack work?
229 retrieved = unpack(format, got)[0]
230 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000231
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000232 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000233 self.assertRaises((struct.error, TypeError), unpack, format,
234 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000235 else:
236 # x is out of range -- verify pack realizes that.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000237 self.assertRaises(struct.error, pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000238
239 def run(self):
240 from random import randrange
241
242 # Create all interesting powers of 2.
243 values = []
244 for exp in range(self.bitsize + 3):
245 values.append(1 << exp)
246
247 # Add some random values.
248 for i in range(self.bitsize):
249 val = 0
250 for j in range(self.bytesize):
251 val = (val << 8) | randrange(256)
252 values.append(val)
253
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000254 # Values absorbed from other tests
255 values.extend([300, 700000, sys.maxsize*4])
256
257 # Try all those, and their negations, and +-1 from
258 # them. Note that this tests all power-of-2
259 # boundaries in range, and a few out of range, plus
260 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000261 for base in values:
262 for val in -base, base:
263 for incr in -1, 0, 1:
264 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000265 self.test_one(x)
266
267 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000268 class NotAnInt:
269 def __int__(self):
270 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000271
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000272 self.assertRaises((TypeError, struct.error),
273 struct.pack, self.format,
274 "a string")
275 self.assertRaises((TypeError, struct.error),
276 struct.pack, self.format,
277 randrange)
278 self.assertRaises((TypeError, struct.error),
279 struct.pack, self.format,
280 3+42j)
281 self.assertRaises((TypeError, struct.error),
282 struct.pack, self.format,
283 NotAnInt)
284
Mark Dickinsonc5935772010-04-03 15:54:36 +0000285 # Objects with an '__index__' method should be allowed
286 # to pack as integers.
287 class Indexable(object):
288 def __init__(self, value):
289 self._value = value
290
291 def __index__(self):
292 return self._value
293
294 for obj in (Indexable(0), Indexable(10), Indexable(17),
295 Indexable(42), Indexable(100), Indexable(127)):
296 try:
297 struct.pack(format, obj)
298 except:
299 self.fail("integer code pack failed on object "
300 "with '__index__' method")
301
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000302 for code in integer_codes:
303 for byteorder in byteorders:
304 if (byteorder in ('', '@') and code in ('q', 'Q') and
305 not HAVE_LONG_LONG):
306 continue
307 format = byteorder+code
308 t = IntTester(format)
309 t.run()
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000310
311 def test_p_code(self):
312 # Test p ("Pascal string") code.
313 for code, input, expected, expectedback in [
314 ('p','abc', '\x00', b''),
315 ('1p', 'abc', '\x00', b''),
316 ('2p', 'abc', '\x01a', b'a'),
317 ('3p', 'abc', '\x02ab', b'ab'),
318 ('4p', 'abc', '\x03abc', b'abc'),
319 ('5p', 'abc', '\x03abc\x00', b'abc'),
320 ('6p', 'abc', '\x03abc\x00\x00', b'abc'),
321 ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]:
322 expected = bytes(expected, "latin-1")
323 got = struct.pack(code, input)
324 self.assertEqual(got, expected)
325 (got,) = struct.unpack(code, got)
326 self.assertEqual(got, expectedback)
327
328 def test_705836(self):
329 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
330 # from the low-order discarded bits could propagate into the exponent
331 # field, causing the result to be wrong by a factor of 2.
332 import math
333
334 for base in range(1, 33):
335 # smaller <- largest representable float less than base.
336 delta = 0.5
337 while base - delta / 2.0 != base:
338 delta /= 2.0
339 smaller = base - delta
340 # Packing this rounds away a solid string of trailing 1 bits.
341 packed = struct.pack("<f", smaller)
342 unpacked = struct.unpack("<f", packed)[0]
343 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
344 # 16, respectively.
345 self.assertEqual(base, unpacked)
346 bigpacked = struct.pack(">f", smaller)
347 self.assertEqual(bigpacked, string_reverse(packed))
348 unpacked = struct.unpack(">f", bigpacked)[0]
349 self.assertEqual(base, unpacked)
350
351 # Largest finite IEEE single.
352 big = (1 << 24) - 1
353 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000354 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000355 unpacked = struct.unpack(">f", packed)[0]
356 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000357
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000358 # The same, but tack on a 1 bit so it rounds up to infinity.
359 big = (1 << 25) - 1
360 big = math.ldexp(big, 127 - 24)
361 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000362
Mark Dickinsonea835e72009-04-19 20:40:33 +0000363 def test_1530559(self):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000364 for byteorder in '', '@', '=', '<', '>', '!':
365 for code in integer_codes:
366 if (byteorder in ('', '@') and code in ('q', 'Q') and
367 not HAVE_LONG_LONG):
368 continue
369 format = byteorder + code
370 self.assertRaises(struct.error, struct.pack, format, 1.0)
371 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000372 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
373 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
374
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000375 def test_unpack_from(self):
376 test_string = b'abcd01234'
377 fmt = '4s'
378 s = struct.Struct(fmt)
379 for cls in (bytes, bytearray):
380 data = cls(test_string)
381 if not isinstance(data, (bytes, bytearray)):
382 bytes_data = bytes(data, 'latin1')
383 else:
384 bytes_data = data
385 self.assertEqual(s.unpack_from(data), (b'abcd',))
386 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
387 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
388 for i in range(6):
389 self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],))
390 for i in range(6, len(test_string) + 1):
391 self.assertRaises(struct.error, s.unpack_from, data, i)
392 for cls in (bytes, bytearray):
393 data = cls(test_string)
394 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
395 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
396 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
397 for i in range(6):
398 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
399 for i in range(6, len(test_string) + 1):
400 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000401
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000402 def test_pack_into(self):
403 test_string = b'Reykjavik rocks, eow!'
404 writable_buf = array.array('b', b' '*100)
405 fmt = '21s'
406 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000407
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000408 # Test without offset
409 s.pack_into(writable_buf, 0, test_string)
410 from_buf = writable_buf.tostring()[:len(test_string)]
411 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000412
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000413 # Test with offset.
414 s.pack_into(writable_buf, 10, test_string)
415 from_buf = writable_buf.tostring()[:len(test_string)+10]
416 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000417
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000418 # Go beyond boundaries.
419 small_buf = array.array('b', b' '*10)
420 self.assertRaises(struct.error, s.pack_into, small_buf, 0, test_string)
421 self.assertRaises(struct.error, s.pack_into, small_buf, 2, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000422
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000423 # Test bogus offset (issue 3694)
424 sb = small_buf
425 self.assertRaises(TypeError, struct.pack_into, b'1', sb, None)
426
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000427 def test_pack_into_fn(self):
428 test_string = b'Reykjavik rocks, eow!'
429 writable_buf = array.array('b', b' '*100)
430 fmt = '21s'
431 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000432
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000433 # Test without offset.
434 pack_into(writable_buf, 0, test_string)
435 from_buf = writable_buf.tostring()[:len(test_string)]
436 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000437
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000438 # Test with offset.
439 pack_into(writable_buf, 10, test_string)
440 from_buf = writable_buf.tostring()[:len(test_string)+10]
441 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000442
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000443 # Go beyond boundaries.
444 small_buf = array.array('b', b' '*10)
445 self.assertRaises(struct.error, pack_into, small_buf, 0, test_string)
446 self.assertRaises(struct.error, pack_into, small_buf, 2, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 def test_unpack_with_buffer(self):
449 # SF bug 1563759: struct.unpack doens't support buffer protocol objects
450 data1 = array.array('B', b'\x12\x34\x56\x78')
451 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
452 for data in [data1, data2]:
453 value, = struct.unpack('>I', data)
454 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000455
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000456 def test_bool(self):
457 for prefix in tuple("<>!=")+('',):
458 false = (), [], [], '', 0
459 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000460
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000461 falseFormat = prefix + '?' * len(false)
462 packedFalse = struct.pack(falseFormat, *false)
463 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000464
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000465 trueFormat = prefix + '?' * len(true)
466 packedTrue = struct.pack(trueFormat, *true)
467 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000468
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000469 self.assertEqual(len(true), len(unpackedTrue))
470 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000471
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000472 for t in unpackedFalse:
473 self.assertFalse(t)
474 for t in unpackedTrue:
475 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000476
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000477 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000478
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000479 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000480
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000481 if len(packed) != 1:
482 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
483 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000484
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000485 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
486 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000487
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000488 if IS32BIT:
489 def test_crasher(self):
490 self.assertRaises(MemoryError, struct.pack, "357913941b", "a")
491
492
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000493def test_main():
494 run_unittest(StructTest)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000495
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000496if __name__ == '__main__':
497 test_main()