1 from collections import abc 2 import array 3 import math 4 import operator 5 import unittest 6 import struct 7 import sys 8 9 from test import support 10 11 ISBIGENDIAN = sys.byteorder == "big" 12 13 integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' 14 byteorders = '', '@', '=', '<', '>', '!' 15 16 def 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 23 def string_reverse(s): 24 return s[::-1] 25 26 def bigendian_to_native(value): 27 if ISBIGENDIAN: 28 return value 29 else: 30 return string_reverse(value) 31 32 class 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', b'') 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', b'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 b'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 def test_boundary_error_message(self): 582 regex = ( 583 r'pack_into requires a buffer of at least 6 ' 584 r'bytes for packing 1 bytes at offset 5 ' 585 r'\(actual buffer size is 1\)' 586 ) 587 with self.assertRaisesRegex(struct.error, regex): 588 struct.pack_into('b', bytearray(1), 5, 1) 589 590 def test_boundary_error_message_with_negative_offset(self): 591 byte_list = bytearray(10) 592 with self.assertRaisesRegex( 593 struct.error, 594 r'no space to pack 4 bytes at offset -2'): 595 struct.pack_into('<I', byte_list, -2, 123) 596 597 with self.assertRaisesRegex( 598 struct.error, 599 'offset -11 out of range for 10-byte buffer'): 600 struct.pack_into('<B', byte_list, -11, 123) 601 602 def test_boundary_error_message_with_large_offset(self): 603 # Test overflows cause by large offset and value size (issue 30245) 604 regex = ( 605 r'pack_into requires a buffer of at least ' + str(sys.maxsize + 4) + 606 r' bytes for packing 4 bytes at offset ' + str(sys.maxsize) + 607 r' \(actual buffer size is 10\)' 608 ) 609 with self.assertRaisesRegex(struct.error, regex): 610 struct.pack_into('<I', bytearray(10), sys.maxsize, 1) 611 612 def test_issue29802(self): 613 # When the second argument of struct.unpack() was of wrong type 614 # the Struct object was decrefed twice and the reference to 615 # deallocated object was left in a cache. 616 with self.assertRaises(TypeError): 617 struct.unpack('b', 0) 618 # Shouldn't crash. 619 self.assertEqual(struct.unpack('b', b'a'), (b'a'[0],)) 620 621 def test_format_attr(self): 622 s = struct.Struct('=i2H') 623 self.assertEqual(s.format, '=i2H') 624 625 # use a bytes string 626 s2 = struct.Struct(s.format.encode()) 627 self.assertEqual(s2.format, s.format) 628 629 630 class UnpackIteratorTest(unittest.TestCase): 631 """ 632 Tests for iterative unpacking (struct.Struct.iter_unpack). 633 """ 634 635 def test_construct(self): 636 def _check_iterator(it): 637 self.assertIsInstance(it, abc.Iterator) 638 self.assertIsInstance(it, abc.Iterable) 639 s = struct.Struct('>ibcp') 640 it = s.iter_unpack(b"") 641 _check_iterator(it) 642 it = s.iter_unpack(b"1234567") 643 _check_iterator(it) 644 # Wrong bytes length 645 with self.assertRaises(struct.error): 646 s.iter_unpack(b"123456") 647 with self.assertRaises(struct.error): 648 s.iter_unpack(b"12345678") 649 # Zero-length struct 650 s = struct.Struct('>') 651 with self.assertRaises(struct.error): 652 s.iter_unpack(b"") 653 with self.assertRaises(struct.error): 654 s.iter_unpack(b"12") 655 656 def test_iterate(self): 657 s = struct.Struct('>IB') 658 b = bytes(range(1, 16)) 659 it = s.iter_unpack(b) 660 self.assertEqual(next(it), (0x01020304, 5)) 661 self.assertEqual(next(it), (0x06070809, 10)) 662 self.assertEqual(next(it), (0x0b0c0d0e, 15)) 663 self.assertRaises(StopIteration, next, it) 664 self.assertRaises(StopIteration, next, it) 665 666 def test_arbitrary_buffer(self): 667 s = struct.Struct('>IB') 668 b = bytes(range(1, 11)) 669 it = s.iter_unpack(memoryview(b)) 670 self.assertEqual(next(it), (0x01020304, 5)) 671 self.assertEqual(next(it), (0x06070809, 10)) 672 self.assertRaises(StopIteration, next, it) 673 self.assertRaises(StopIteration, next, it) 674 675 def test_length_hint(self): 676 lh = operator.length_hint 677 s = struct.Struct('>IB') 678 b = bytes(range(1, 16)) 679 it = s.iter_unpack(b) 680 self.assertEqual(lh(it), 3) 681 next(it) 682 self.assertEqual(lh(it), 2) 683 next(it) 684 self.assertEqual(lh(it), 1) 685 next(it) 686 self.assertEqual(lh(it), 0) 687 self.assertRaises(StopIteration, next, it) 688 self.assertEqual(lh(it), 0) 689 690 def test_module_func(self): 691 # Sanity check for the global struct.iter_unpack() 692 it = struct.iter_unpack('>IB', bytes(range(1, 11))) 693 self.assertEqual(next(it), (0x01020304, 5)) 694 self.assertEqual(next(it), (0x06070809, 10)) 695 self.assertRaises(StopIteration, next, it) 696 self.assertRaises(StopIteration, next, it) 697 698 def test_half_float(self): 699 # Little-endian examples from: 700 # http://en.wikipedia.org/wiki/Half_precision_floating-point_format 701 format_bits_float__cleanRoundtrip_list = [ 702 (b'\x00\x3c', 1.0), 703 (b'\x00\xc0', -2.0), 704 (b'\xff\x7b', 65504.0), # (max half precision) 705 (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal) 706 (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal) 707 (b'\x00\x00', 0.0), 708 (b'\x00\x80', -0.0), 709 (b'\x00\x7c', float('+inf')), 710 (b'\x00\xfc', float('-inf')), 711 (b'\x55\x35', 0.333251953125), # ~= 1/3 712 ] 713 714 for le_bits, f in format_bits_float__cleanRoundtrip_list: 715 be_bits = le_bits[::-1] 716 self.assertEqual(f, struct.unpack('<e', le_bits)[0]) 717 self.assertEqual(le_bits, struct.pack('<e', f)) 718 self.assertEqual(f, struct.unpack('>e', be_bits)[0]) 719 self.assertEqual(be_bits, struct.pack('>e', f)) 720 if sys.byteorder == 'little': 721 self.assertEqual(f, struct.unpack('e', le_bits)[0]) 722 self.assertEqual(le_bits, struct.pack('e', f)) 723 else: 724 self.assertEqual(f, struct.unpack('e', be_bits)[0]) 725 self.assertEqual(be_bits, struct.pack('e', f)) 726 727 # Check for NaN handling: 728 format_bits__nan_list = [ 729 ('<e', b'\x01\xfc'), 730 ('<e', b'\x00\xfe'), 731 ('<e', b'\xff\xff'), 732 ('<e', b'\x01\x7c'), 733 ('<e', b'\x00\x7e'), 734 ('<e', b'\xff\x7f'), 735 ] 736 737 for formatcode, bits in format_bits__nan_list: 738 self.assertTrue(math.isnan(struct.unpack('<e', bits)[0])) 739 self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0])) 740 741 # Check that packing produces a bit pattern representing a quiet NaN: 742 # all exponent bits and the msb of the fraction should all be 1. 743 packed = struct.pack('<e', math.nan) 744 self.assertEqual(packed[1] & 0x7e, 0x7e) 745 packed = struct.pack('<e', -math.nan) 746 self.assertEqual(packed[1] & 0x7e, 0x7e) 747 748 # Checks for round-to-even behavior 749 format_bits_float__rounding_list = [ 750 ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal 751 ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode) 752 ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero 753 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal. 754 ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65), 755 ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25), 756 ('>e', b'\x04\x00', 2.0**-14), # Smallest normal. 757 ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10) 758 ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode) 759 ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0 760 ('>e', b'\x7b\xff', 65504), # largest normal 761 ('>e', b'\x7b\xff', 65519), # rounds to 65504 762 ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal 763 ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode) 764 ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero 765 ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10) 766 ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode) 767 ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0 768 ('>e', b'\xfb\xff', -65519), # rounds to 65504 769 ] 770 771 for formatcode, bits, f in format_bits_float__rounding_list: 772 self.assertEqual(bits, struct.pack(formatcode, f)) 773 774 # This overflows, and so raises an error 775 format_bits_float__roundingError_list = [ 776 # Values that round to infinity. 777 ('>e', 65520.0), 778 ('>e', 65536.0), 779 ('>e', 1e300), 780 ('>e', -65520.0), 781 ('>e', -65536.0), 782 ('>e', -1e300), 783 ('<e', 65520.0), 784 ('<e', 65536.0), 785 ('<e', 1e300), 786 ('<e', -65520.0), 787 ('<e', -65536.0), 788 ('<e', -1e300), 789 ] 790 791 for formatcode, f in format_bits_float__roundingError_list: 792 self.assertRaises(OverflowError, struct.pack, formatcode, f) 793 794 # Double rounding 795 format_bits_float__doubleRoundingError_list = [ 796 ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048 797 ] 798 799 for formatcode, bits, f in format_bits_float__doubleRoundingError_list: 800 self.assertEqual(bits, struct.pack(formatcode, f)) 801 802 803 if __name__ == '__main__': 804 unittest.main() 805