1from collections import abc 2import array 3import math 4import operator 5import unittest 6import struct 7import sys 8 9from test import support 10 11ISBIGENDIAN = sys.byteorder == "big" 12 13integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' 14byteorders = '', '@', '=', '<', '>', '!' 15 16def iter_integer_formats(byteorders=byteorders): 17 for code in integer_codes: 18 for byteorder in byteorders: 19 if (byteorder not in ('', '@') and code in ('n', 'N')): 20 continue 21 yield code, byteorder 22 23def string_reverse(s): 24 return s[::-1] 25 26def bigendian_to_native(value): 27 if ISBIGENDIAN: 28 return value 29 else: 30 return string_reverse(value) 31 32class StructTest(unittest.TestCase): 33 def test_isbigendian(self): 34 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) 35 36 def test_consistence(self): 37 self.assertRaises(struct.error, struct.calcsize, 'Z') 38 39 sz = struct.calcsize('i') 40 self.assertEqual(sz * 3, struct.calcsize('iii')) 41 42 fmt = 'cbxxxxxxhhhhiillffd?' 43 fmt3 = '3c3b18x12h6i6l6f3d3?' 44 sz = struct.calcsize(fmt) 45 sz3 = struct.calcsize(fmt3) 46 self.assertEqual(sz * 3, sz3) 47 48 self.assertRaises(struct.error, struct.pack, 'iii', 3) 49 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3) 50 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo') 51 self.assertRaises((TypeError, 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) 56 57 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 66 67 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) 80 81 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', b'a', b'a', b'a', 0), 86 ('xc', b'a', b'\0a', b'\0a', 0), 87 ('cx', b'a', b'a\0', b'a\0', 0), 88 ('s', b'a', b'a', b'a', 0), 89 ('0s', b'helloworld', b'', b'', 1), 90 ('1s', b'helloworld', b'h', b'h', 1), 91 ('9s', b'helloworld', b'helloworl', b'helloworl', 1), 92 ('10s', b'helloworld', b'helloworld', b'helloworld', 0), 93 ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1), 94 ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1), 95 ('b', 7, b'\7', b'\7', 0), 96 ('b', -7, b'\371', b'\371', 0), 97 ('B', 7, b'\7', b'\7', 0), 98 ('B', 249, b'\371', b'\371', 0), 99 ('h', 700, b'\002\274', b'\274\002', 0), 100 ('h', -700, b'\375D', b'D\375', 0), 101 ('H', 700, b'\002\274', b'\274\002', 0), 102 ('H', 0x10000-700, b'\375D', b'D\375', 0), 103 ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 104 ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 105 ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 106 ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 107 ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 108 ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 109 ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 110 ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 111 ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0), 112 ('d', 2.0, b'@\000\000\000\000\000\000\000', 113 b'\000\000\000\000\000\000\000@', 0), 114 ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0), 115 ('d', -2.0, b'\300\000\000\000\000\000\000\000', 116 b'\000\000\000\000\000\000\000\300', 0), 117 ('?', 0, b'\0', b'\0', 0), 118 ('?', 3, b'\1', b'\1', 1), 119 ('?', True, b'\1', b'\1', 0), 120 ('?', [], b'\0', b'\0', 1), 121 ('?', (1,), b'\1', b'\1', 1), 122 ] 123 124 for fmt, arg, big, lil, asy in tests: 125 for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), 126 ('='+fmt, ISBIGENDIAN and big or lil)]: 127 res = struct.pack(xfmt, arg) 128 self.assertEqual(res, exp) 129 self.assertEqual(struct.calcsize(xfmt), len(res)) 130 rev = struct.unpack(xfmt, res)[0] 131 if rev != arg: 132 self.assertTrue(asy) 133 134 def test_calcsize(self): 135 expected_size = { 136 'b': 1, 'B': 1, 137 'h': 2, 'H': 2, 138 'i': 4, 'I': 4, 139 'l': 4, 'L': 4, 140 'q': 8, 'Q': 8, 141 } 142 143 # standard integer sizes 144 for code, byteorder in iter_integer_formats(('=', '<', '>', '!')): 145 format = byteorder+code 146 size = struct.calcsize(format) 147 self.assertEqual(size, expected_size[code]) 148 149 # native integer sizes 150 native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN', 'qQ' 151 for format_pair in native_pairs: 152 for byteorder in '', '@': 153 signed_size = struct.calcsize(byteorder + format_pair[0]) 154 unsigned_size = struct.calcsize(byteorder + format_pair[1]) 155 self.assertEqual(signed_size, unsigned_size) 156 157 # bounds for native integer sizes 158 self.assertEqual(struct.calcsize('b'), 1) 159 self.assertLessEqual(2, struct.calcsize('h')) 160 self.assertLessEqual(4, struct.calcsize('l')) 161 self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i')) 162 self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l')) 163 self.assertLessEqual(8, struct.calcsize('q')) 164 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q')) 165 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i')) 166 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P')) 167 168 def test_integers(self): 169 # Integer tests (bBhHiIlLqQnN). 170 import binascii 171 172 class IntTester(unittest.TestCase): 173 def __init__(self, format): 174 super(IntTester, self).__init__(methodName='test_one') 175 self.format = format 176 self.code = format[-1] 177 self.byteorder = format[:-1] 178 if not self.byteorder in byteorders: 179 raise ValueError("unrecognized packing byteorder: %s" % 180 self.byteorder) 181 self.bytesize = struct.calcsize(format) 182 self.bitsize = self.bytesize * 8 183 if self.code in tuple('bhilqn'): 184 self.signed = True 185 self.min_value = -(2**(self.bitsize-1)) 186 self.max_value = 2**(self.bitsize-1) - 1 187 elif self.code in tuple('BHILQN'): 188 self.signed = False 189 self.min_value = 0 190 self.max_value = 2**self.bitsize - 1 191 else: 192 raise ValueError("unrecognized format code: %s" % 193 self.code) 194 195 def test_one(self, x, pack=struct.pack, 196 unpack=struct.unpack, 197 unhexlify=binascii.unhexlify): 198 199 format = self.format 200 if self.min_value <= x <= self.max_value: 201 expected = x 202 if self.signed and x < 0: 203 expected += 1 << self.bitsize 204 self.assertGreaterEqual(expected, 0) 205 expected = '%x' % expected 206 if len(expected) & 1: 207 expected = "0" + expected 208 expected = expected.encode('ascii') 209 expected = unhexlify(expected) 210 expected = (b"\x00" * (self.bytesize - len(expected)) + 211 expected) 212 if (self.byteorder == '<' or 213 self.byteorder in ('', '@', '=') and not ISBIGENDIAN): 214 expected = string_reverse(expected) 215 self.assertEqual(len(expected), self.bytesize) 216 217 # Pack work? 218 got = pack(format, x) 219 self.assertEqual(got, expected) 220 221 # Unpack work? 222 retrieved = unpack(format, got)[0] 223 self.assertEqual(x, retrieved) 224 225 # Adding any byte should cause a "too big" error. 226 self.assertRaises((struct.error, TypeError), unpack, format, 227 b'\x01' + got) 228 else: 229 # x is out of range -- verify pack realizes that. 230 self.assertRaises((OverflowError, ValueError, struct.error), 231 pack, format, x) 232 233 def run(self): 234 from random import randrange 235 236 # Create all interesting powers of 2. 237 values = [] 238 for exp in range(self.bitsize + 3): 239 values.append(1 << exp) 240 241 # Add some random values. 242 for i in range(self.bitsize): 243 val = 0 244 for j in range(self.bytesize): 245 val = (val << 8) | randrange(256) 246 values.append(val) 247 248 # Values absorbed from other tests 249 values.extend([300, 700000, sys.maxsize*4]) 250 251 # Try all those, and their negations, and +-1 from 252 # them. Note that this tests all power-of-2 253 # boundaries in range, and a few out of range, plus 254 # +-(2**n +- 1). 255 for base in values: 256 for val in -base, base: 257 for incr in -1, 0, 1: 258 x = val + incr 259 self.test_one(x) 260 261 # Some error cases. 262 class NotAnInt: 263 def __int__(self): 264 return 42 265 266 # Objects with an '__index__' method should be allowed 267 # to pack as integers. That is assuming the implemented 268 # '__index__' method returns an 'int'. 269 class Indexable(object): 270 def __init__(self, value): 271 self._value = value 272 273 def __index__(self): 274 return self._value 275 276 # If the '__index__' method raises a type error, then 277 # '__int__' should be used with a deprecation warning. 278 class BadIndex(object): 279 def __index__(self): 280 raise TypeError 281 282 def __int__(self): 283 return 42 284 285 self.assertRaises((TypeError, struct.error), 286 struct.pack, self.format, 287 "a string") 288 self.assertRaises((TypeError, struct.error), 289 struct.pack, self.format, 290 randrange) 291 self.assertRaises((TypeError, struct.error), 292 struct.pack, self.format, 293 3+42j) 294 self.assertRaises((TypeError, struct.error), 295 struct.pack, self.format, 296 NotAnInt()) 297 self.assertRaises((TypeError, struct.error), 298 struct.pack, self.format, 299 BadIndex()) 300 301 # Check for legitimate values from '__index__'. 302 for obj in (Indexable(0), Indexable(10), Indexable(17), 303 Indexable(42), Indexable(100), Indexable(127)): 304 try: 305 struct.pack(format, obj) 306 except: 307 self.fail("integer code pack failed on object " 308 "with '__index__' method") 309 310 # Check for bogus values from '__index__'. 311 for obj in (Indexable(b'a'), Indexable('b'), Indexable(None), 312 Indexable({'a': 1}), Indexable([1, 2, 3])): 313 self.assertRaises((TypeError, struct.error), 314 struct.pack, self.format, 315 obj) 316 317 for code, byteorder in iter_integer_formats(): 318 format = byteorder+code 319 t = IntTester(format) 320 t.run() 321 322 def test_nN_code(self): 323 # n and N don't exist in standard sizes 324 def assertStructError(func, *args, **kwargs): 325 with self.assertRaises(struct.error) as cm: 326 func(*args, **kwargs) 327 self.assertIn("bad char in struct format", str(cm.exception)) 328 for code in 'nN': 329 for byteorder in ('=', '<', '>', '!'): 330 format = byteorder+code 331 assertStructError(struct.calcsize, format) 332 assertStructError(struct.pack, format, 0) 333 assertStructError(struct.unpack, format, b"") 334 335 def test_p_code(self): 336 # Test p ("Pascal string") code. 337 for code, input, expected, expectedback in [ 338 ('p', b'abc', b'\x00', b''), 339 ('1p', b'abc', b'\x00', b''), 340 ('2p', b'abc', b'\x01a', b'a'), 341 ('3p', b'abc', b'\x02ab', b'ab'), 342 ('4p', b'abc', b'\x03abc', b'abc'), 343 ('5p', b'abc', b'\x03abc\x00', b'abc'), 344 ('6p', b'abc', b'\x03abc\x00\x00', b'abc'), 345 ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]: 346 got = struct.pack(code, input) 347 self.assertEqual(got, expected) 348 (got,) = struct.unpack(code, got) 349 self.assertEqual(got, expectedback) 350 351 def test_705836(self): 352 # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry 353 # from the low-order discarded bits could propagate into the exponent 354 # field, causing the result to be wrong by a factor of 2. 355 for base in range(1, 33): 356 # smaller <- largest representable float less than base. 357 delta = 0.5 358 while base - delta / 2.0 != base: 359 delta /= 2.0 360 smaller = base - delta 361 # Packing this rounds away a solid string of trailing 1 bits. 362 packed = struct.pack("<f", smaller) 363 unpacked = struct.unpack("<f", packed)[0] 364 # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and 365 # 16, respectively. 366 self.assertEqual(base, unpacked) 367 bigpacked = struct.pack(">f", smaller) 368 self.assertEqual(bigpacked, string_reverse(packed)) 369 unpacked = struct.unpack(">f", bigpacked)[0] 370 self.assertEqual(base, unpacked) 371 372 # Largest finite IEEE single. 373 big = (1 << 24) - 1 374 big = math.ldexp(big, 127 - 23) 375 packed = struct.pack(">f", big) 376 unpacked = struct.unpack(">f", packed)[0] 377 self.assertEqual(big, unpacked) 378 379 # The same, but tack on a 1 bit so it rounds up to infinity. 380 big = (1 << 25) - 1 381 big = math.ldexp(big, 127 - 24) 382 self.assertRaises(OverflowError, struct.pack, ">f", big) 383 384 def test_1530559(self): 385 for code, byteorder in iter_integer_formats(): 386 format = byteorder + code 387 self.assertRaises(struct.error, struct.pack, format, 1.0) 388 self.assertRaises(struct.error, struct.pack, format, 1.5) 389 self.assertRaises(struct.error, struct.pack, 'P', 1.0) 390 self.assertRaises(struct.error, struct.pack, 'P', 1.5) 391 392 def test_unpack_from(self): 393 test_string = b'abcd01234' 394 fmt = '4s' 395 s = struct.Struct(fmt) 396 for cls in (bytes, bytearray): 397 data = cls(test_string) 398 self.assertEqual(s.unpack_from(data), (b'abcd',)) 399 self.assertEqual(s.unpack_from(data, 2), (b'cd01',)) 400 self.assertEqual(s.unpack_from(data, 4), (b'0123',)) 401 for i in range(6): 402 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],)) 403 for i in range(6, len(test_string) + 1): 404 self.assertRaises(struct.error, s.unpack_from, data, i) 405 for cls in (bytes, bytearray): 406 data = cls(test_string) 407 self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',)) 408 self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',)) 409 self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',)) 410 for i in range(6): 411 self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],)) 412 for i in range(6, len(test_string) + 1): 413 self.assertRaises(struct.error, struct.unpack_from, fmt, data, i) 414 415 # keyword arguments 416 self.assertEqual(s.unpack_from(buffer=test_string, offset=2), 417 (b'cd01',)) 418 419 def test_pack_into(self): 420 test_string = b'Reykjavik rocks, eow!' 421 writable_buf = array.array('b', b' '*100) 422 fmt = '21s' 423 s = struct.Struct(fmt) 424 425 # Test without offset 426 s.pack_into(writable_buf, 0, test_string) 427 from_buf = writable_buf.tobytes()[:len(test_string)] 428 self.assertEqual(from_buf, test_string) 429 430 # Test with offset. 431 s.pack_into(writable_buf, 10, test_string) 432 from_buf = writable_buf.tobytes()[:len(test_string)+10] 433 self.assertEqual(from_buf, test_string[:10] + test_string) 434 435 # Go beyond boundaries. 436 small_buf = array.array('b', b' '*10) 437 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0, 438 test_string) 439 self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2, 440 test_string) 441 442 # Test bogus offset (issue 3694) 443 sb = small_buf 444 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb, 445 None) 446 447 def test_pack_into_fn(self): 448 test_string = b'Reykjavik rocks, eow!' 449 writable_buf = array.array('b', b' '*100) 450 fmt = '21s' 451 pack_into = lambda *args: struct.pack_into(fmt, *args) 452 453 # Test without offset. 454 pack_into(writable_buf, 0, test_string) 455 from_buf = writable_buf.tobytes()[:len(test_string)] 456 self.assertEqual(from_buf, test_string) 457 458 # Test with offset. 459 pack_into(writable_buf, 10, test_string) 460 from_buf = writable_buf.tobytes()[:len(test_string)+10] 461 self.assertEqual(from_buf, test_string[:10] + test_string) 462 463 # Go beyond boundaries. 464 small_buf = array.array('b', b' '*10) 465 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0, 466 test_string) 467 self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2, 468 test_string) 469 470 def test_unpack_with_buffer(self): 471 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects 472 data1 = array.array('B', b'\x12\x34\x56\x78') 473 data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4 474 for data in [data1, data2]: 475 value, = struct.unpack('>I', data) 476 self.assertEqual(value, 0x12345678) 477 478 def test_bool(self): 479 class ExplodingBool(object): 480 def __bool__(self): 481 raise OSError 482 for prefix in tuple("<>!=")+('',): 483 false = (), [], [], '', 0 484 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2 485 486 falseFormat = prefix + '?' * len(false) 487 packedFalse = struct.pack(falseFormat, *false) 488 unpackedFalse = struct.unpack(falseFormat, packedFalse) 489 490 trueFormat = prefix + '?' * len(true) 491 packedTrue = struct.pack(trueFormat, *true) 492 unpackedTrue = struct.unpack(trueFormat, packedTrue) 493 494 self.assertEqual(len(true), len(unpackedTrue)) 495 self.assertEqual(len(false), len(unpackedFalse)) 496 497 for t in unpackedFalse: 498 self.assertFalse(t) 499 for t in unpackedTrue: 500 self.assertTrue(t) 501 502 packed = struct.pack(prefix+'?', 1) 503 504 self.assertEqual(len(packed), struct.calcsize(prefix+'?')) 505 506 if len(packed) != 1: 507 self.assertFalse(prefix, msg='encoded bool is not one byte: %r' 508 %packed) 509 510 try: 511 struct.pack(prefix + '?', ExplodingBool()) 512 except OSError: 513 pass 514 else: 515 self.fail("Expected OSError: struct.pack(%r, " 516 "ExplodingBool())" % (prefix + '?')) 517 518 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']: 519 self.assertTrue(struct.unpack('>?', c)[0]) 520 521 def test_count_overflow(self): 522 hugecount = '{}b'.format(sys.maxsize+1) 523 self.assertRaises(struct.error, struct.calcsize, hugecount) 524 525 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) 526 self.assertRaises(struct.error, struct.calcsize, hugecount2) 527 528 def test_trailing_counter(self): 529 store = array.array('b', b' '*100) 530 531 # format lists containing only count spec should result in an error 532 self.assertRaises(struct.error, struct.pack, '12345') 533 self.assertRaises(struct.error, struct.unpack, '12345', '') 534 self.assertRaises(struct.error, struct.pack_into, '12345', store, 0) 535 self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0) 536 537 # Format lists with trailing count spec should result in an error 538 self.assertRaises(struct.error, struct.pack, 'c12345', 'x') 539 self.assertRaises(struct.error, struct.unpack, 'c12345', 'x') 540 self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0, 541 'x') 542 self.assertRaises(struct.error, struct.unpack_from, 'c12345', store, 543 0) 544 545 # Mixed format tests 546 self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs') 547 self.assertRaises(struct.error, struct.unpack, '14s42', 548 'spam and eggs') 549 self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0, 550 'spam and eggs') 551 self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0) 552 553 def test_Struct_reinitialization(self): 554 # Issue 9422: there was a memory leak when reinitializing a 555 # Struct instance. This test can be used to detect the leak 556 # when running with regrtest -L. 557 s = struct.Struct('i') 558 s.__init__('ii') 559 560 def check_sizeof(self, format_str, number_of_codes): 561 # The size of 'PyStructObject' 562 totalsize = support.calcobjsize('2n3P') 563 # The size taken up by the 'formatcode' dynamic array 564 totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1) 565 support.check_sizeof(self, struct.Struct(format_str), totalsize) 566 567 @support.cpython_only 568 def test__sizeof__(self): 569 for code in integer_codes: 570 self.check_sizeof(code, 1) 571 self.check_sizeof('BHILfdspP', 9) 572 self.check_sizeof('B' * 1234, 1234) 573 self.check_sizeof('fd', 2) 574 self.check_sizeof('xxxxxxxxxxxxxx', 0) 575 self.check_sizeof('100H', 1) 576 self.check_sizeof('187s', 1) 577 self.check_sizeof('20p', 1) 578 self.check_sizeof('0s', 1) 579 self.check_sizeof('0c', 0) 580 581 582class UnpackIteratorTest(unittest.TestCase): 583 """ 584 Tests for iterative unpacking (struct.Struct.iter_unpack). 585 """ 586 587 def test_construct(self): 588 def _check_iterator(it): 589 self.assertIsInstance(it, abc.Iterator) 590 self.assertIsInstance(it, abc.Iterable) 591 s = struct.Struct('>ibcp') 592 it = s.iter_unpack(b"") 593 _check_iterator(it) 594 it = s.iter_unpack(b"1234567") 595 _check_iterator(it) 596 # Wrong bytes length 597 with self.assertRaises(struct.error): 598 s.iter_unpack(b"123456") 599 with self.assertRaises(struct.error): 600 s.iter_unpack(b"12345678") 601 # Zero-length struct 602 s = struct.Struct('>') 603 with self.assertRaises(struct.error): 604 s.iter_unpack(b"") 605 with self.assertRaises(struct.error): 606 s.iter_unpack(b"12") 607 608 def test_iterate(self): 609 s = struct.Struct('>IB') 610 b = bytes(range(1, 16)) 611 it = s.iter_unpack(b) 612 self.assertEqual(next(it), (0x01020304, 5)) 613 self.assertEqual(next(it), (0x06070809, 10)) 614 self.assertEqual(next(it), (0x0b0c0d0e, 15)) 615 self.assertRaises(StopIteration, next, it) 616 self.assertRaises(StopIteration, next, it) 617 618 def test_arbitrary_buffer(self): 619 s = struct.Struct('>IB') 620 b = bytes(range(1, 11)) 621 it = s.iter_unpack(memoryview(b)) 622 self.assertEqual(next(it), (0x01020304, 5)) 623 self.assertEqual(next(it), (0x06070809, 10)) 624 self.assertRaises(StopIteration, next, it) 625 self.assertRaises(StopIteration, next, it) 626 627 def test_length_hint(self): 628 lh = operator.length_hint 629 s = struct.Struct('>IB') 630 b = bytes(range(1, 16)) 631 it = s.iter_unpack(b) 632 self.assertEqual(lh(it), 3) 633 next(it) 634 self.assertEqual(lh(it), 2) 635 next(it) 636 self.assertEqual(lh(it), 1) 637 next(it) 638 self.assertEqual(lh(it), 0) 639 self.assertRaises(StopIteration, next, it) 640 self.assertEqual(lh(it), 0) 641 642 def test_module_func(self): 643 # Sanity check for the global struct.iter_unpack() 644 it = struct.iter_unpack('>IB', bytes(range(1, 11))) 645 self.assertEqual(next(it), (0x01020304, 5)) 646 self.assertEqual(next(it), (0x06070809, 10)) 647 self.assertRaises(StopIteration, next, it) 648 self.assertRaises(StopIteration, next, it) 649 650 def test_half_float(self): 651 # Little-endian examples from: 652 # http://en.wikipedia.org/wiki/Half_precision_floating-point_format 653 format_bits_float__cleanRoundtrip_list = [ 654 (b'\x00\x3c', 1.0), 655 (b'\x00\xc0', -2.0), 656 (b'\xff\x7b', 65504.0), # (max half precision) 657 (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal) 658 (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal) 659 (b'\x00\x00', 0.0), 660 (b'\x00\x80', -0.0), 661 (b'\x00\x7c', float('+inf')), 662 (b'\x00\xfc', float('-inf')), 663 (b'\x55\x35', 0.333251953125), # ~= 1/3 664 ] 665 666 for le_bits, f in format_bits_float__cleanRoundtrip_list: 667 be_bits = le_bits[::-1] 668 self.assertEqual(f, struct.unpack('<e', le_bits)[0]) 669 self.assertEqual(le_bits, struct.pack('<e', f)) 670 self.assertEqual(f, struct.unpack('>e', be_bits)[0]) 671 self.assertEqual(be_bits, struct.pack('>e', f)) 672 if sys.byteorder == 'little': 673 self.assertEqual(f, struct.unpack('e', le_bits)[0]) 674 self.assertEqual(le_bits, struct.pack('e', f)) 675 else: 676 self.assertEqual(f, struct.unpack('e', be_bits)[0]) 677 self.assertEqual(be_bits, struct.pack('e', f)) 678 679 # Check for NaN handling: 680 format_bits__nan_list = [ 681 ('<e', b'\x01\xfc'), 682 ('<e', b'\x00\xfe'), 683 ('<e', b'\xff\xff'), 684 ('<e', b'\x01\x7c'), 685 ('<e', b'\x00\x7e'), 686 ('<e', b'\xff\x7f'), 687 ] 688 689 for formatcode, bits in format_bits__nan_list: 690 self.assertTrue(math.isnan(struct.unpack('<e', bits)[0])) 691 self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0])) 692 693 # Check that packing produces a bit pattern representing a quiet NaN: 694 # all exponent bits and the msb of the fraction should all be 1. 695 packed = struct.pack('<e', math.nan) 696 self.assertEqual(packed[1] & 0x7e, 0x7e) 697 packed = struct.pack('<e', -math.nan) 698 self.assertEqual(packed[1] & 0x7e, 0x7e) 699 700 # Checks for round-to-even behavior 701 format_bits_float__rounding_list = [ 702 ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal 703 ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode) 704 ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero 705 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal. 706 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65), 707 ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25), 708 ('>e', b'\x04\x00', 2.0**-14), # Smallest normal. 709 ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10) 710 ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode) 711 ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0 712 ('>e', b'\x7b\xff', 65504), # largest normal 713 ('>e', b'\x7b\xff', 65519), # rounds to 65504 714 ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal 715 ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode) 716 ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero 717 ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10) 718 ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode) 719 ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0 720 ('>e', b'\xfb\xff', -65519), # rounds to 65504 721 ] 722 723 for formatcode, bits, f in format_bits_float__rounding_list: 724 self.assertEqual(bits, struct.pack(formatcode, f)) 725 726 # This overflows, and so raises an error 727 format_bits_float__roundingError_list = [ 728 # Values that round to infinity. 729 ('>e', 65520.0), 730 ('>e', 65536.0), 731 ('>e', 1e300), 732 ('>e', -65520.0), 733 ('>e', -65536.0), 734 ('>e', -1e300), 735 ('<e', 65520.0), 736 ('<e', 65536.0), 737 ('<e', 1e300), 738 ('<e', -65520.0), 739 ('<e', -65536.0), 740 ('<e', -1e300), 741 ] 742 743 for formatcode, f in format_bits_float__roundingError_list: 744 self.assertRaises(OverflowError, struct.pack, formatcode, f) 745 746 # Double rounding 747 format_bits_float__doubleRoundingError_list = [ 748 ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048 749 ] 750 751 for formatcode, bits, f in format_bits_float__doubleRoundingError_list: 752 self.assertEqual(bits, struct.pack(formatcode, f)) 753 754 755if __name__ == '__main__': 756 unittest.main() 757