blob: b3f21ea7db49ef3d2aed55489cba5c985e3a2db9 [file] [log] [blame]
Antoine Pitrou9f146812013-04-27 00:20:04 +02001from collections import abc
Thomas Wouters477c8d52006-05-27 19:21:47 +00002import array
Mark Dickinson7c4e4092016-09-03 17:21:29 +01003import math
Antoine Pitrou9f146812013-04-27 00:20:04 +02004import operator
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +00005import unittest
6import struct
Tim Peters17e17d42001-06-13 22:45:27 +00007import sys
Mark Dickinson79d38ac2010-03-05 14:44:08 +00008
Martin v. Löwis33f79972012-07-29 16:33:05 +02009from test import support
Eddie Elizondo4590f722020-02-04 02:29:25 -080010from test.support.script_helper import assert_python_ok
Mark Dickinson79d38ac2010-03-05 14:44:08 +000011
Tim Peters17e17d42001-06-13 22:45:27 +000012ISBIGENDIAN = sys.byteorder == "big"
Tim Peters17e17d42001-06-13 22:45:27 +000013
Antoine Pitrou45d9c912011-10-06 15:27:40 +020014integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +000015byteorders = '', '@', '=', '<', '>', '!'
16
Antoine Pitrou45d9c912011-10-06 15:27:40 +020017def iter_integer_formats(byteorders=byteorders):
18 for code in integer_codes:
19 for byteorder in byteorders:
Antoine Pitrou45d9c912011-10-06 15:27:40 +020020 if (byteorder not in ('', '@') and code in ('n', 'N')):
21 continue
22 yield code, byteorder
23
Tim Peters17e17d42001-06-13 22:45:27 +000024def string_reverse(s):
Guido van Rossume625fd52007-05-27 09:19:04 +000025 return s[::-1]
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
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000033class StructTest(unittest.TestCase):
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000034 def test_isbigendian(self):
Amaury Forgeot d'Arcf9f29822008-06-17 21:56:01 +000035 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
Tim Peters7a3bfc32001-06-12 01:22:22 +000036
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000037 def test_consistence(self):
38 self.assertRaises(struct.error, struct.calcsize, 'Z')
Tim Peters7a3bfc32001-06-12 01:22:22 +000039
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000040 sz = struct.calcsize('i')
41 self.assertEqual(sz * 3, struct.calcsize('iii'))
Tim Peters7a3bfc32001-06-12 01:22:22 +000042
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000043 fmt = 'cbxxxxxxhhhhiillffd?'
44 fmt3 = '3c3b18x12h6i6l6f3d3?'
45 sz = struct.calcsize(fmt)
46 sz3 = struct.calcsize(fmt3)
47 self.assertEqual(sz * 3, sz3)
Tim Peters7a3bfc32001-06-12 01:22:22 +000048
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000049 self.assertRaises(struct.error, struct.pack, 'iii', 3)
50 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3)
Benjamin Petersona04a32d2010-07-09 13:28:42 +000051 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo')
52 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000053 self.assertRaises(struct.error, struct.unpack, 'd', b'flap')
54 s = struct.pack('ii', 1, 2)
55 self.assertRaises(struct.error, struct.unpack, 'iii', s)
56 self.assertRaises(struct.error, struct.unpack, 'i', s)
Tim Peters7a3bfc32001-06-12 01:22:22 +000057
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000058 def test_transitiveness(self):
59 c = b'a'
60 b = 1
61 h = 255
62 i = 65535
63 l = 65536
64 f = 3.1415
65 d = 3.1415
66 t = True
Tim Peters7a3bfc32001-06-12 01:22:22 +000067
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000068 for prefix in ('', '@', '<', '>', '=', '!'):
69 for format in ('xcbhilfd?', 'xcBHILfd?'):
70 format = prefix + format
71 s = struct.pack(format, c, b, h, i, l, f, d, t)
72 cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
73 self.assertEqual(cp, c)
74 self.assertEqual(bp, b)
75 self.assertEqual(hp, h)
76 self.assertEqual(ip, i)
77 self.assertEqual(lp, l)
78 self.assertEqual(int(100 * fp), int(100 * f))
79 self.assertEqual(int(100 * dp), int(100 * d))
80 self.assertEqual(tp, t)
Tim Peters7a3bfc32001-06-12 01:22:22 +000081
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +000082 def test_new_features(self):
83 # Test some of the new features in detail
84 # (format, argument, big-endian result, little-endian result, asymmetric)
85 tests = [
Victor Stinnerda9ec992010-12-28 13:26:42 +000086 ('c', b'a', b'a', b'a', 0),
87 ('xc', b'a', b'\0a', b'\0a', 0),
88 ('cx', b'a', b'a\0', b'a\0', 0),
89 ('s', b'a', b'a', b'a', 0),
90 ('0s', b'helloworld', b'', b'', 1),
91 ('1s', b'helloworld', b'h', b'h', 1),
92 ('9s', b'helloworld', b'helloworl', b'helloworl', 1),
93 ('10s', b'helloworld', b'helloworld', b'helloworld', 0),
94 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
95 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
96 ('b', 7, b'\7', b'\7', 0),
97 ('b', -7, b'\371', b'\371', 0),
98 ('B', 7, b'\7', b'\7', 0),
99 ('B', 249, b'\371', b'\371', 0),
100 ('h', 700, b'\002\274', b'\274\002', 0),
101 ('h', -700, b'\375D', b'D\375', 0),
102 ('H', 700, b'\002\274', b'\274\002', 0),
103 ('H', 0x10000-700, b'\375D', b'D\375', 0),
104 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
105 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
106 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
107 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
108 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
109 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
110 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0),
111 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0),
112 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0),
113 ('d', 2.0, b'@\000\000\000\000\000\000\000',
114 b'\000\000\000\000\000\000\000@', 0),
115 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0),
116 ('d', -2.0, b'\300\000\000\000\000\000\000\000',
117 b'\000\000\000\000\000\000\000\300', 0),
118 ('?', 0, b'\0', b'\0', 0),
119 ('?', 3, b'\1', b'\1', 1),
120 ('?', True, b'\1', b'\1', 0),
121 ('?', [], b'\0', b'\0', 1),
122 ('?', (1,), b'\1', b'\1', 1),
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000123 ]
Tim Peters7a3bfc32001-06-12 01:22:22 +0000124
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000125 for fmt, arg, big, lil, asy in tests:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000126 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
127 ('='+fmt, ISBIGENDIAN and big or lil)]:
128 res = struct.pack(xfmt, arg)
129 self.assertEqual(res, exp)
130 self.assertEqual(struct.calcsize(xfmt), len(res))
131 rev = struct.unpack(xfmt, res)[0]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000132 if rev != arg:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000133 self.assertTrue(asy)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000134
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000135 def test_calcsize(self):
136 expected_size = {
137 'b': 1, 'B': 1,
138 'h': 2, 'H': 2,
139 'i': 4, 'I': 4,
140 'l': 4, 'L': 4,
141 'q': 8, 'Q': 8,
142 }
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000143
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000144 # standard integer sizes
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200145 for code, byteorder in iter_integer_formats(('=', '<', '>', '!')):
146 format = byteorder+code
147 size = struct.calcsize(format)
148 self.assertEqual(size, expected_size[code])
Tim Peters7a3bfc32001-06-12 01:22:22 +0000149
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000150 # native integer sizes
Benjamin Petersoned4aa832016-09-05 17:44:18 -0700151 native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN', 'qQ'
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000152 for format_pair in native_pairs:
153 for byteorder in '', '@':
154 signed_size = struct.calcsize(byteorder + format_pair[0])
155 unsigned_size = struct.calcsize(byteorder + format_pair[1])
156 self.assertEqual(signed_size, unsigned_size)
157
158 # bounds for native integer sizes
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000159 self.assertEqual(struct.calcsize('b'), 1)
160 self.assertLessEqual(2, struct.calcsize('h'))
161 self.assertLessEqual(4, struct.calcsize('l'))
162 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i'))
163 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l'))
Benjamin Petersoned4aa832016-09-05 17:44:18 -0700164 self.assertLessEqual(8, struct.calcsize('q'))
165 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q'))
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200166 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i'))
167 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P'))
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000168
169 def test_integers(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200170 # Integer tests (bBhHiIlLqQnN).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000171 import binascii
Tim Peters17e17d42001-06-13 22:45:27 +0000172
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000173 class IntTester(unittest.TestCase):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000174 def __init__(self, format):
Benjamin Peterson7fe73a12009-04-04 16:35:46 +0000175 super(IntTester, self).__init__(methodName='test_one')
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000176 self.format = format
177 self.code = format[-1]
178 self.byteorder = format[:-1]
179 if not self.byteorder in byteorders:
180 raise ValueError("unrecognized packing byteorder: %s" %
181 self.byteorder)
182 self.bytesize = struct.calcsize(format)
183 self.bitsize = self.bytesize * 8
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200184 if self.code in tuple('bhilqn'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000185 self.signed = True
186 self.min_value = -(2**(self.bitsize-1))
187 self.max_value = 2**(self.bitsize-1) - 1
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200188 elif self.code in tuple('BHILQN'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000189 self.signed = False
190 self.min_value = 0
191 self.max_value = 2**self.bitsize - 1
192 else:
193 raise ValueError("unrecognized format code: %s" %
194 self.code)
Tim Peters17e17d42001-06-13 22:45:27 +0000195
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000196 def test_one(self, x, pack=struct.pack,
197 unpack=struct.unpack,
198 unhexlify=binascii.unhexlify):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000199
200 format = self.format
201 if self.min_value <= x <= self.max_value:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000202 expected = x
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000203 if self.signed and x < 0:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000204 expected += 1 << self.bitsize
Ezio Melotti4c28ddc2010-04-04 07:21:15 +0000205 self.assertGreaterEqual(expected, 0)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000206 expected = '%x' % expected
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000207 if len(expected) & 1:
208 expected = "0" + expected
Florent Xiclunaf1046ca2010-07-27 21:20:15 +0000209 expected = expected.encode('ascii')
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000210 expected = unhexlify(expected)
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000211 expected = (b"\x00" * (self.bytesize - len(expected)) +
212 expected)
213 if (self.byteorder == '<' or
214 self.byteorder in ('', '@', '=') and not ISBIGENDIAN):
215 expected = string_reverse(expected)
216 self.assertEqual(len(expected), self.bytesize)
Tim Peters0891ac02001-09-15 02:35:15 +0000217
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000218 # Pack work?
219 got = pack(format, x)
220 self.assertEqual(got, expected)
Tim Petersd50ade62003-03-20 18:32:13 +0000221
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000222 # Unpack work?
223 retrieved = unpack(format, got)[0]
224 self.assertEqual(x, retrieved)
Tim Petersd50ade62003-03-20 18:32:13 +0000225
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000226 # Adding any byte should cause a "too big" error.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000227 self.assertRaises((struct.error, TypeError), unpack, format,
228 b'\x01' + got)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000229 else:
230 # x is out of range -- verify pack realizes that.
Benjamin Peterson0d62f5b2010-07-10 15:14:45 +0000231 self.assertRaises((OverflowError, ValueError, struct.error),
232 pack, format, x)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000233
234 def run(self):
235 from random import randrange
236
237 # Create all interesting powers of 2.
238 values = []
239 for exp in range(self.bitsize + 3):
240 values.append(1 << exp)
241
242 # Add some random values.
243 for i in range(self.bitsize):
244 val = 0
245 for j in range(self.bytesize):
246 val = (val << 8) | randrange(256)
247 values.append(val)
248
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000249 # Values absorbed from other tests
250 values.extend([300, 700000, sys.maxsize*4])
251
252 # Try all those, and their negations, and +-1 from
253 # them. Note that this tests all power-of-2
254 # boundaries in range, and a few out of range, plus
255 # +-(2**n +- 1).
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000256 for base in values:
257 for val in -base, base:
258 for incr in -1, 0, 1:
259 x = val + incr
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000260 self.test_one(x)
261
262 # Some error cases.
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000263 class NotAnInt:
264 def __int__(self):
265 return 42
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000266
Mark Dickinsone9493a12010-04-04 08:52:51 +0000267 # Objects with an '__index__' method should be allowed
268 # to pack as integers. That is assuming the implemented
Serhiy Storchaka95949422013-08-27 19:40:23 +0300269 # '__index__' method returns an 'int'.
Mark Dickinsone9493a12010-04-04 08:52:51 +0000270 class Indexable(object):
271 def __init__(self, value):
272 self._value = value
273
274 def __index__(self):
275 return self._value
276
277 # If the '__index__' method raises a type error, then
278 # '__int__' should be used with a deprecation warning.
279 class BadIndex(object):
280 def __index__(self):
281 raise TypeError
282
283 def __int__(self):
284 return 42
285
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000286 self.assertRaises((TypeError, struct.error),
287 struct.pack, self.format,
288 "a string")
289 self.assertRaises((TypeError, struct.error),
290 struct.pack, self.format,
291 randrange)
292 self.assertRaises((TypeError, struct.error),
293 struct.pack, self.format,
294 3+42j)
295 self.assertRaises((TypeError, struct.error),
296 struct.pack, self.format,
Mark Dickinsone9493a12010-04-04 08:52:51 +0000297 NotAnInt())
298 self.assertRaises((TypeError, struct.error),
299 struct.pack, self.format,
300 BadIndex())
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000301
Mark Dickinsone9493a12010-04-04 08:52:51 +0000302 # Check for legitimate values from '__index__'.
Mark Dickinsonc5935772010-04-03 15:54:36 +0000303 for obj in (Indexable(0), Indexable(10), Indexable(17),
304 Indexable(42), Indexable(100), Indexable(127)):
305 try:
306 struct.pack(format, obj)
307 except:
308 self.fail("integer code pack failed on object "
309 "with '__index__' method")
310
Mark Dickinsone9493a12010-04-04 08:52:51 +0000311 # Check for bogus values from '__index__'.
312 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None),
313 Indexable({'a': 1}), Indexable([1, 2, 3])):
314 self.assertRaises((TypeError, struct.error),
315 struct.pack, self.format,
316 obj)
317
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200318 for code, byteorder in iter_integer_formats():
319 format = byteorder+code
320 t = IntTester(format)
321 t.run()
322
323 def test_nN_code(self):
324 # n and N don't exist in standard sizes
325 def assertStructError(func, *args, **kwargs):
326 with self.assertRaises(struct.error) as cm:
327 func(*args, **kwargs)
328 self.assertIn("bad char in struct format", str(cm.exception))
329 for code in 'nN':
330 for byteorder in ('=', '<', '>', '!'):
Mark Dickinsonb9f751a2010-04-03 15:07:40 +0000331 format = byteorder+code
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200332 assertStructError(struct.calcsize, format)
333 assertStructError(struct.pack, format, 0)
334 assertStructError(struct.unpack, format, b"")
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000335
336 def test_p_code(self):
337 # Test p ("Pascal string") code.
338 for code, input, expected, expectedback in [
Victor Stinnerda9ec992010-12-28 13:26:42 +0000339 ('p', b'abc', b'\x00', b''),
340 ('1p', b'abc', b'\x00', b''),
341 ('2p', b'abc', b'\x01a', b'a'),
342 ('3p', b'abc', b'\x02ab', b'ab'),
343 ('4p', b'abc', b'\x03abc', b'abc'),
344 ('5p', b'abc', b'\x03abc\x00', b'abc'),
345 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'),
346 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]:
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000347 got = struct.pack(code, input)
348 self.assertEqual(got, expected)
349 (got,) = struct.unpack(code, got)
350 self.assertEqual(got, expectedback)
351
352 def test_705836(self):
353 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
354 # from the low-order discarded bits could propagate into the exponent
355 # field, causing the result to be wrong by a factor of 2.
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000356 for base in range(1, 33):
357 # smaller <- largest representable float less than base.
358 delta = 0.5
359 while base - delta / 2.0 != base:
360 delta /= 2.0
361 smaller = base - delta
362 # Packing this rounds away a solid string of trailing 1 bits.
363 packed = struct.pack("<f", smaller)
364 unpacked = struct.unpack("<f", packed)[0]
365 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and
366 # 16, respectively.
367 self.assertEqual(base, unpacked)
368 bigpacked = struct.pack(">f", smaller)
369 self.assertEqual(bigpacked, string_reverse(packed))
370 unpacked = struct.unpack(">f", bigpacked)[0]
371 self.assertEqual(base, unpacked)
372
373 # Largest finite IEEE single.
374 big = (1 << 24) - 1
375 big = math.ldexp(big, 127 - 23)
Tim Petersd50ade62003-03-20 18:32:13 +0000376 packed = struct.pack(">f", big)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000377 unpacked = struct.unpack(">f", packed)[0]
378 self.assertEqual(big, unpacked)
Tim Petersd50ade62003-03-20 18:32:13 +0000379
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000380 # The same, but tack on a 1 bit so it rounds up to infinity.
381 big = (1 << 25) - 1
382 big = math.ldexp(big, 127 - 24)
383 self.assertRaises(OverflowError, struct.pack, ">f", big)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000384
Mark Dickinsonea835e72009-04-19 20:40:33 +0000385 def test_1530559(self):
Antoine Pitrou45d9c912011-10-06 15:27:40 +0200386 for code, byteorder in iter_integer_formats():
387 format = byteorder + code
388 self.assertRaises(struct.error, struct.pack, format, 1.0)
389 self.assertRaises(struct.error, struct.pack, format, 1.5)
Mark Dickinsonea835e72009-04-19 20:40:33 +0000390 self.assertRaises(struct.error, struct.pack, 'P', 1.0)
391 self.assertRaises(struct.error, struct.pack, 'P', 1.5)
392
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000393 def test_unpack_from(self):
394 test_string = b'abcd01234'
395 fmt = '4s'
396 s = struct.Struct(fmt)
397 for cls in (bytes, bytearray):
398 data = cls(test_string)
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000399 self.assertEqual(s.unpack_from(data), (b'abcd',))
400 self.assertEqual(s.unpack_from(data, 2), (b'cd01',))
401 self.assertEqual(s.unpack_from(data, 4), (b'0123',))
402 for i in range(6):
Victor Stinnerda9ec992010-12-28 13:26:42 +0000403 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],))
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000404 for i in range(6, len(test_string) + 1):
405 self.assertRaises(struct.error, s.unpack_from, data, i)
406 for cls in (bytes, bytearray):
407 data = cls(test_string)
408 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',))
409 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',))
410 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',))
411 for i in range(6):
412 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],))
413 for i in range(6, len(test_string) + 1):
414 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000415
Victor Stinner3f2d1012017-02-02 12:09:30 +0100416 # keyword arguments
417 self.assertEqual(s.unpack_from(buffer=test_string, offset=2),
418 (b'cd01',))
419
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000420 def test_pack_into(self):
421 test_string = b'Reykjavik rocks, eow!'
422 writable_buf = array.array('b', b' '*100)
423 fmt = '21s'
424 s = struct.Struct(fmt)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000425
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000426 # Test without offset
427 s.pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000428 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000429 self.assertEqual(from_buf, test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000430
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000431 # Test with offset.
432 s.pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000433 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000434 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000435
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000436 # Go beyond boundaries.
437 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000438 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
439 test_string)
440 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
441 test_string)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000442
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000443 # Test bogus offset (issue 3694)
444 sb = small_buf
Benjamin Peterson4b83af92010-07-09 13:31:11 +0000445 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
446 None)
Georg Brandl75c3d6f2009-02-13 11:01:07 +0000447
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000448 def test_pack_into_fn(self):
449 test_string = b'Reykjavik rocks, eow!'
450 writable_buf = array.array('b', b' '*100)
451 fmt = '21s'
452 pack_into = lambda *args: struct.pack_into(fmt, *args)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000453
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000454 # Test without offset.
455 pack_into(writable_buf, 0, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000456 from_buf = writable_buf.tobytes()[:len(test_string)]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000457 self.assertEqual(from_buf, test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000458
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000459 # Test with offset.
460 pack_into(writable_buf, 10, test_string)
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000461 from_buf = writable_buf.tobytes()[:len(test_string)+10]
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000462 self.assertEqual(from_buf, test_string[:10] + test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000463
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000464 # Go beyond boundaries.
465 small_buf = array.array('b', b' '*10)
Benjamin Peterson6ef08a02010-07-07 22:45:06 +0000466 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0,
467 test_string)
468 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
469 test_string)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000470
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000471 def test_unpack_with_buffer(self):
Ezio Melotti13925002011-03-16 11:05:33 +0200472 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000473 data1 = array.array('B', b'\x12\x34\x56\x78')
474 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4
475 for data in [data1, data2]:
476 value, = struct.unpack('>I', data)
477 self.assertEqual(value, 0x12345678)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000478
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000479 def test_bool(self):
Benjamin Petersonde73c452010-07-07 18:54:59 +0000480 class ExplodingBool(object):
481 def __bool__(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200482 raise OSError
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000483 for prefix in tuple("<>!=")+('',):
484 false = (), [], [], '', 0
485 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2
Thomas Wouters477c8d52006-05-27 19:21:47 +0000486
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000487 falseFormat = prefix + '?' * len(false)
488 packedFalse = struct.pack(falseFormat, *false)
489 unpackedFalse = struct.unpack(falseFormat, packedFalse)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000490
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000491 trueFormat = prefix + '?' * len(true)
492 packedTrue = struct.pack(trueFormat, *true)
493 unpackedTrue = struct.unpack(trueFormat, packedTrue)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000494
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000495 self.assertEqual(len(true), len(unpackedTrue))
496 self.assertEqual(len(false), len(unpackedFalse))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000497
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000498 for t in unpackedFalse:
499 self.assertFalse(t)
500 for t in unpackedTrue:
501 self.assertTrue(t)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000502
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000503 packed = struct.pack(prefix+'?', 1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000504
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000505 self.assertEqual(len(packed), struct.calcsize(prefix+'?'))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000506
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000507 if len(packed) != 1:
508 self.assertFalse(prefix, msg='encoded bool is not one byte: %r'
509 %packed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000510
Mark Dickinson94628ee2010-07-12 20:03:24 +0000511 try:
512 struct.pack(prefix + '?', ExplodingBool())
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200513 except OSError:
Mark Dickinson94628ee2010-07-12 20:03:24 +0000514 pass
515 else:
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200516 self.fail("Expected OSError: struct.pack(%r, "
Mark Dickinson94628ee2010-07-12 20:03:24 +0000517 "ExplodingBool())" % (prefix + '?'))
Benjamin Petersonde73c452010-07-07 18:54:59 +0000518
Benjamin Petersonc937dc22010-07-07 18:44:05 +0000519 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']:
520 self.assertTrue(struct.unpack('>?', c)[0])
Thomas Woutersb2137042007-02-01 18:02:27 +0000521
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000522 def test_count_overflow(self):
523 hugecount = '{}b'.format(sys.maxsize+1)
524 self.assertRaises(struct.error, struct.calcsize, hugecount)
525
Mark Dickinsonb72e6862010-06-11 19:50:30 +0000526 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
527 self.assertRaises(struct.error, struct.calcsize, hugecount2)
Mark Dickinsonab4096f2010-06-11 16:56:34 +0000528
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000529 def test_trailing_counter(self):
530 store = array.array('b', b' '*100)
531
532 # format lists containing only count spec should result in an error
533 self.assertRaises(struct.error, struct.pack, '12345')
Victor Stinnerc0f59ad2017-02-02 14:24:16 +0100534 self.assertRaises(struct.error, struct.unpack, '12345', b'')
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000535 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0)
536 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0)
537
538 # Format lists with trailing count spec should result in an error
539 self.assertRaises(struct.error, struct.pack, 'c12345', 'x')
Victor Stinnerc0f59ad2017-02-02 14:24:16 +0100540 self.assertRaises(struct.error, struct.unpack, 'c12345', b'x')
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000541 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0,
542 'x')
543 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store,
544 0)
545
546 # Mixed format tests
547 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs')
548 self.assertRaises(struct.error, struct.unpack, '14s42',
Victor Stinnerc0f59ad2017-02-02 14:24:16 +0100549 b'spam and eggs')
Alexander Belopolsky177e8532010-06-11 16:04:59 +0000550 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0,
551 'spam and eggs')
552 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0)
553
Mark Dickinson5b1d35b2010-08-01 11:10:28 +0000554 def test_Struct_reinitialization(self):
555 # Issue 9422: there was a memory leak when reinitializing a
556 # Struct instance. This test can be used to detect the leak
557 # when running with regrtest -L.
558 s = struct.Struct('i')
559 s.__init__('ii')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000560
Martin v. Löwis33f79972012-07-29 16:33:05 +0200561 def check_sizeof(self, format_str, number_of_codes):
562 # The size of 'PyStructObject'
Martin v. Löwis2b168442012-07-29 16:38:45 +0200563 totalsize = support.calcobjsize('2n3P')
Martin v. Löwis33f79972012-07-29 16:33:05 +0200564 # The size taken up by the 'formatcode' dynamic array
Serhiy Storchakafff61f22013-05-17 10:49:44 +0300565 totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1)
Martin v. Löwis33f79972012-07-29 16:33:05 +0200566 support.check_sizeof(self, struct.Struct(format_str), totalsize)
567
568 @support.cpython_only
Meador Inge90bc2dbc2012-07-28 22:16:39 -0500569 def test__sizeof__(self):
570 for code in integer_codes:
571 self.check_sizeof(code, 1)
572 self.check_sizeof('BHILfdspP', 9)
573 self.check_sizeof('B' * 1234, 1234)
574 self.check_sizeof('fd', 2)
575 self.check_sizeof('xxxxxxxxxxxxxx', 0)
Serhiy Storchakafff61f22013-05-17 10:49:44 +0300576 self.check_sizeof('100H', 1)
Meador Inge90bc2dbc2012-07-28 22:16:39 -0500577 self.check_sizeof('187s', 1)
578 self.check_sizeof('20p', 1)
579 self.check_sizeof('0s', 1)
580 self.check_sizeof('0c', 0)
Meador Ingeb14d8c92012-07-23 10:01:29 -0500581
Andrew Nesterf78b1192017-04-04 13:46:25 +0300582 def test_boundary_error_message(self):
Xiang Zhangc10b2882018-03-11 02:58:52 +0800583 regex1 = (
Andrew Nesterf78b1192017-04-04 13:46:25 +0300584 r'pack_into requires a buffer of at least 6 '
585 r'bytes for packing 1 bytes at offset 5 '
586 r'\(actual buffer size is 1\)'
587 )
Xiang Zhangc10b2882018-03-11 02:58:52 +0800588 with self.assertRaisesRegex(struct.error, regex1):
Andrew Nesterf78b1192017-04-04 13:46:25 +0300589 struct.pack_into('b', bytearray(1), 5, 1)
590
Xiang Zhangc10b2882018-03-11 02:58:52 +0800591 regex2 = (
592 r'unpack_from requires a buffer of at least 6 '
593 r'bytes for unpacking 1 bytes at offset 5 '
594 r'\(actual buffer size is 1\)'
595 )
596 with self.assertRaisesRegex(struct.error, regex2):
597 struct.unpack_from('b', bytearray(1), 5)
598
Andrew Nesterf78b1192017-04-04 13:46:25 +0300599 def test_boundary_error_message_with_negative_offset(self):
600 byte_list = bytearray(10)
601 with self.assertRaisesRegex(
602 struct.error,
603 r'no space to pack 4 bytes at offset -2'):
604 struct.pack_into('<I', byte_list, -2, 123)
605
606 with self.assertRaisesRegex(
607 struct.error,
608 'offset -11 out of range for 10-byte buffer'):
609 struct.pack_into('<B', byte_list, -11, 123)
Antoine Pitrou9f146812013-04-27 00:20:04 +0200610
Xiang Zhangc10b2882018-03-11 02:58:52 +0800611 with self.assertRaisesRegex(
612 struct.error,
613 r'not enough data to unpack 4 bytes at offset -2'):
614 struct.unpack_from('<I', byte_list, -2)
615
616 with self.assertRaisesRegex(
617 struct.error,
618 "offset -11 out of range for 10-byte buffer"):
619 struct.unpack_from('<B', byte_list, -11)
620
Johan Liuaead53b2017-06-02 14:33:04 +0800621 def test_boundary_error_message_with_large_offset(self):
622 # Test overflows cause by large offset and value size (issue 30245)
Xiang Zhangc10b2882018-03-11 02:58:52 +0800623 regex1 = (
Johan Liuaead53b2017-06-02 14:33:04 +0800624 r'pack_into requires a buffer of at least ' + str(sys.maxsize + 4) +
625 r' bytes for packing 4 bytes at offset ' + str(sys.maxsize) +
626 r' \(actual buffer size is 10\)'
627 )
Xiang Zhangc10b2882018-03-11 02:58:52 +0800628 with self.assertRaisesRegex(struct.error, regex1):
Johan Liuaead53b2017-06-02 14:33:04 +0800629 struct.pack_into('<I', bytearray(10), sys.maxsize, 1)
630
Xiang Zhangc10b2882018-03-11 02:58:52 +0800631 regex2 = (
632 r'unpack_from requires a buffer of at least ' + str(sys.maxsize + 4) +
633 r' bytes for unpacking 4 bytes at offset ' + str(sys.maxsize) +
634 r' \(actual buffer size is 10\)'
635 )
636 with self.assertRaisesRegex(struct.error, regex2):
637 struct.unpack_from('<I', bytearray(10), sys.maxsize)
638
Serhiy Storchaka40db90c2017-04-20 21:19:31 +0300639 def test_issue29802(self):
640 # When the second argument of struct.unpack() was of wrong type
641 # the Struct object was decrefed twice and the reference to
642 # deallocated object was left in a cache.
643 with self.assertRaises(TypeError):
Serhiy Storchaka73c47082017-10-21 21:59:23 +0300644 struct.unpack('b', 0)
Serhiy Storchaka40db90c2017-04-20 21:19:31 +0300645 # Shouldn't crash.
Serhiy Storchaka73c47082017-10-21 21:59:23 +0300646 self.assertEqual(struct.unpack('b', b'a'), (b'a'[0],))
Serhiy Storchaka40db90c2017-04-20 21:19:31 +0300647
Victor Stinnerf87b85f2017-06-23 15:11:12 +0200648 def test_format_attr(self):
649 s = struct.Struct('=i2H')
650 self.assertEqual(s.format, '=i2H')
651
652 # use a bytes string
653 s2 = struct.Struct(s.format.encode())
654 self.assertEqual(s2.format, s.format)
655
Eddie Elizondo4590f722020-02-04 02:29:25 -0800656 def test_struct_cleans_up_at_runtime_shutdown(self):
657 code = """if 1:
658 import struct
659
660 class C:
661 def __init__(self):
662 self.pack = struct.pack
663 def __del__(self):
664 self.pack('I', -42)
665
666 struct.x = C()
667 """
668 rc, stdout, stderr = assert_python_ok("-c", code)
669 self.assertEqual(rc, 0)
670 self.assertEqual(stdout.rstrip(), b"")
671 self.assertIn(b"Exception ignored in:", stderr)
672 self.assertIn(b"C.__del__", stderr)
Serhiy Storchaka40db90c2017-04-20 21:19:31 +0300673
Zackery Spytz3f59b552020-05-25 01:55:09 -0600674 def test_issue35714(self):
675 # Embedded null characters should not be allowed in format strings.
676 for s in '\0', '2\0i', b'\0':
677 with self.assertRaisesRegex(struct.error,
678 'embedded null character'):
679 struct.calcsize(s)
680
681
Antoine Pitrou9f146812013-04-27 00:20:04 +0200682class UnpackIteratorTest(unittest.TestCase):
683 """
684 Tests for iterative unpacking (struct.Struct.iter_unpack).
685 """
686
687 def test_construct(self):
688 def _check_iterator(it):
689 self.assertIsInstance(it, abc.Iterator)
690 self.assertIsInstance(it, abc.Iterable)
691 s = struct.Struct('>ibcp')
692 it = s.iter_unpack(b"")
693 _check_iterator(it)
694 it = s.iter_unpack(b"1234567")
695 _check_iterator(it)
696 # Wrong bytes length
697 with self.assertRaises(struct.error):
698 s.iter_unpack(b"123456")
699 with self.assertRaises(struct.error):
700 s.iter_unpack(b"12345678")
701 # Zero-length struct
702 s = struct.Struct('>')
703 with self.assertRaises(struct.error):
704 s.iter_unpack(b"")
705 with self.assertRaises(struct.error):
706 s.iter_unpack(b"12")
707
Dino Viehland4f384af2019-09-10 11:18:37 +0100708 def test_uninstantiable(self):
709 iter_unpack_type = type(struct.Struct(">ibcp").iter_unpack(b""))
710 self.assertRaises(TypeError, iter_unpack_type)
711
Antoine Pitrou9f146812013-04-27 00:20:04 +0200712 def test_iterate(self):
713 s = struct.Struct('>IB')
714 b = bytes(range(1, 16))
715 it = s.iter_unpack(b)
716 self.assertEqual(next(it), (0x01020304, 5))
717 self.assertEqual(next(it), (0x06070809, 10))
718 self.assertEqual(next(it), (0x0b0c0d0e, 15))
719 self.assertRaises(StopIteration, next, it)
720 self.assertRaises(StopIteration, next, it)
721
722 def test_arbitrary_buffer(self):
723 s = struct.Struct('>IB')
724 b = bytes(range(1, 11))
725 it = s.iter_unpack(memoryview(b))
726 self.assertEqual(next(it), (0x01020304, 5))
727 self.assertEqual(next(it), (0x06070809, 10))
728 self.assertRaises(StopIteration, next, it)
729 self.assertRaises(StopIteration, next, it)
730
731 def test_length_hint(self):
732 lh = operator.length_hint
733 s = struct.Struct('>IB')
734 b = bytes(range(1, 16))
735 it = s.iter_unpack(b)
736 self.assertEqual(lh(it), 3)
737 next(it)
738 self.assertEqual(lh(it), 2)
739 next(it)
740 self.assertEqual(lh(it), 1)
741 next(it)
742 self.assertEqual(lh(it), 0)
743 self.assertRaises(StopIteration, next, it)
744 self.assertEqual(lh(it), 0)
745
746 def test_module_func(self):
747 # Sanity check for the global struct.iter_unpack()
748 it = struct.iter_unpack('>IB', bytes(range(1, 11)))
749 self.assertEqual(next(it), (0x01020304, 5))
750 self.assertEqual(next(it), (0x06070809, 10))
751 self.assertRaises(StopIteration, next, it)
752 self.assertRaises(StopIteration, next, it)
753
Mark Dickinson7c4e4092016-09-03 17:21:29 +0100754 def test_half_float(self):
755 # Little-endian examples from:
756 # http://en.wikipedia.org/wiki/Half_precision_floating-point_format
757 format_bits_float__cleanRoundtrip_list = [
758 (b'\x00\x3c', 1.0),
759 (b'\x00\xc0', -2.0),
760 (b'\xff\x7b', 65504.0), # (max half precision)
761 (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal)
762 (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal)
763 (b'\x00\x00', 0.0),
764 (b'\x00\x80', -0.0),
765 (b'\x00\x7c', float('+inf')),
766 (b'\x00\xfc', float('-inf')),
767 (b'\x55\x35', 0.333251953125), # ~= 1/3
768 ]
769
770 for le_bits, f in format_bits_float__cleanRoundtrip_list:
771 be_bits = le_bits[::-1]
772 self.assertEqual(f, struct.unpack('<e', le_bits)[0])
773 self.assertEqual(le_bits, struct.pack('<e', f))
774 self.assertEqual(f, struct.unpack('>e', be_bits)[0])
775 self.assertEqual(be_bits, struct.pack('>e', f))
776 if sys.byteorder == 'little':
777 self.assertEqual(f, struct.unpack('e', le_bits)[0])
778 self.assertEqual(le_bits, struct.pack('e', f))
779 else:
780 self.assertEqual(f, struct.unpack('e', be_bits)[0])
781 self.assertEqual(be_bits, struct.pack('e', f))
782
783 # Check for NaN handling:
784 format_bits__nan_list = [
785 ('<e', b'\x01\xfc'),
786 ('<e', b'\x00\xfe'),
787 ('<e', b'\xff\xff'),
788 ('<e', b'\x01\x7c'),
789 ('<e', b'\x00\x7e'),
790 ('<e', b'\xff\x7f'),
791 ]
792
793 for formatcode, bits in format_bits__nan_list:
794 self.assertTrue(math.isnan(struct.unpack('<e', bits)[0]))
795 self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0]))
796
797 # Check that packing produces a bit pattern representing a quiet NaN:
798 # all exponent bits and the msb of the fraction should all be 1.
799 packed = struct.pack('<e', math.nan)
800 self.assertEqual(packed[1] & 0x7e, 0x7e)
801 packed = struct.pack('<e', -math.nan)
802 self.assertEqual(packed[1] & 0x7e, 0x7e)
803
804 # Checks for round-to-even behavior
805 format_bits_float__rounding_list = [
806 ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal
807 ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode)
808 ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero
809 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal.
810 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65),
811 ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25),
812 ('>e', b'\x04\x00', 2.0**-14), # Smallest normal.
813 ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10)
814 ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode)
815 ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0
816 ('>e', b'\x7b\xff', 65504), # largest normal
817 ('>e', b'\x7b\xff', 65519), # rounds to 65504
818 ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal
819 ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode)
820 ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero
821 ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10)
822 ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode)
823 ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0
824 ('>e', b'\xfb\xff', -65519), # rounds to 65504
825 ]
826
827 for formatcode, bits, f in format_bits_float__rounding_list:
828 self.assertEqual(bits, struct.pack(formatcode, f))
829
830 # This overflows, and so raises an error
831 format_bits_float__roundingError_list = [
832 # Values that round to infinity.
833 ('>e', 65520.0),
834 ('>e', 65536.0),
835 ('>e', 1e300),
836 ('>e', -65520.0),
837 ('>e', -65536.0),
838 ('>e', -1e300),
839 ('<e', 65520.0),
840 ('<e', 65536.0),
841 ('<e', 1e300),
842 ('<e', -65520.0),
843 ('<e', -65536.0),
844 ('<e', -1e300),
845 ]
846
847 for formatcode, f in format_bits_float__roundingError_list:
848 self.assertRaises(OverflowError, struct.pack, formatcode, f)
849
850 # Double rounding
851 format_bits_float__doubleRoundingError_list = [
852 ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048
853 ]
854
855 for formatcode, bits, f in format_bits_float__doubleRoundingError_list:
856 self.assertEqual(bits, struct.pack(formatcode, f))
857
Antoine Pitrou9f146812013-04-27 00:20:04 +0200858
Amaury Forgeot d'Arcfdfe62d2008-06-17 20:36:03 +0000859if __name__ == '__main__':
Zachary Ware38c707e2015-04-13 15:00:43 -0500860 unittest.main()