1from collections import abc 2import array 3import math 4import operator 5import unittest 6import struct 7import sys 8 9from test import support 10from test.support.script_helper import assert_python_ok 11 12ISBIGENDIAN = sys.byteorder == "big" 13 14integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' 15byteorders = '', '@', '=', '<', '>', '!' 16 17def iter_integer_formats(byteorders=byteorders): 18 for code in integer_codes: 19 for byteorder in byteorders: 20 if (byteorder not in ('', '@') and code in ('n', 'N')): 21 continue 22 yield code, byteorder 23 24def string_reverse(s): 25 return s[::-1] 26 27def bigendian_to_native(value): 28 if ISBIGENDIAN: 29 return value 30 else: 31 return string_reverse(value) 32 33class StructTest(unittest.TestCase): 34 def test_isbigendian(self): 35 self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) 36 37 def test_consistence(self): 38 self.assertRaises(struct.error, struct.calcsize, 'Z') 39 40 sz = struct.calcsize('i') 41 self.assertEqual(sz * 3, struct.calcsize('iii')) 42 43 fmt = 'cbxxxxxxhhhhiillffd?' 44 fmt3 = '3c3b18x12h6i6l6f3d3?' 45 sz = struct.calcsize(fmt) 46 sz3 = struct.calcsize(fmt3) 47 self.assertEqual(sz * 3, sz3) 48 49 self.assertRaises(struct.error, struct.pack, 'iii', 3) 50 self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3) 51 self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo') 52 self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo') 53 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) 57 58 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 67 68 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) 81 82 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 = [ 86 ('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), 123 ] 124 125 for fmt, arg, big, lil, asy in tests: 126 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] 132 if rev != arg: 133 self.assertTrue(asy) 134 135 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 } 143 144 # standard integer sizes 145 for code, byteorder in iter_integer_formats(('=', '<', '>', '!')): 146 format = byteorder+code 147 size = struct.calcsize(format) 148 self.assertEqual(size, expected_size[code]) 149 150 # native integer sizes 151 native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN', 'qQ' 152 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 159 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')) 164 self.assertLessEqual(8, struct.calcsize('q')) 165 self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q')) 166 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i')) 167 self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P')) 168 169 def test_integers(self): 170 # Integer tests (bBhHiIlLqQnN). 171 import binascii 172 173 class IntTester(unittest.TestCase): 174 def __init__(self, format): 175 super(IntTester, self).__init__(methodName='test_one') 176 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 184 if self.code in tuple('bhilqn'): 185 self.signed = True 186 self.min_value = -(2**(self.bitsize-1)) 187 self.max_value = 2**(self.bitsize-1) - 1 188 elif self.code in tuple('BHILQN'): 189 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) 195 196 def test_one(self, x, pack=struct.pack, 197 unpack=struct.unpack, 198 unhexlify=binascii.unhexlify): 199 200 format = self.format 201 if self.min_value <= x <= self.max_value: 202 expected = x 203 if self.signed and x < 0: 204 expected += 1 << self.bitsize 205 self.assertGreaterEqual(expected, 0) 206 expected = '%x' % expected 207 if len(expected) & 1: 208 expected = "0" + expected 209 expected = expected.encode('ascii') 210 expected = unhexlify(expected) 211 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) 217 218 # Pack work? 219 got = pack(format, x) 220 self.assertEqual(got, expected) 221 222 # Unpack work? 223 retrieved = unpack(format, got)[0] 224 self.assertEqual(x, retrieved) 225 226 # Adding any byte should cause a "too big" error. 227 self.assertRaises((struct.error, TypeError), unpack, format, 228 b'\x01' + got) 229 else: 230 # x is out of range -- verify pack realizes that. 231 self.assertRaises((OverflowError, ValueError, struct.error), 232 pack, format, x) 233 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 249 # 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). 256 for base in values: 257 for val in -base, base: 258 for incr in -1, 0, 1: 259 x = val + incr 260 self.test_one(x) 261 262 # Some error cases. 263 class NotAnInt: 264 def __int__(self): 265 return 42 266 267 # Objects with an '__index__' method should be allowed 268 # to pack as integers. That is assuming the implemented 269 # '__index__' method returns an 'int'. 270 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 286 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, 297 NotAnInt()) 298 self.assertRaises((TypeError, struct.error), 299 struct.pack, self.format, 300 BadIndex()) 301 302 # Check for legitimate values from '__index__'. 303 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 311 # 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 318 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 ('=', '<', '>', '!'): 331 format = byteorder+code 332 assertStructError(struct.calcsize, format) 333 assertStructError(struct.pack, format, 0) 334 assertStructError(struct.unpack, format, b"") 335 336 def test_p_code(self): 337 # Test p ("Pascal string") code. 338 for code, input, expected, expectedback in [ 339 ('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)]: 347 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. 356 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) 376 packed = struct.pack(">f", big) 377 unpacked = struct.unpack(">f", packed)[0] 378 self.assertEqual(big, unpacked) 379 380 # 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) 384 385 def test_1530559(self): 386 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) 390 self.assertRaises(struct.error, struct.pack, 'P', 1.0) 391 self.assertRaises(struct.error, struct.pack, 'P', 1.5) 392 393 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) 399 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): 403 self.assertEqual(s.unpack_from(data, i), (data[i:i+4],)) 404 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) 415 416 # keyword arguments 417 self.assertEqual(s.unpack_from(buffer=test_string, offset=2), 418 (b'cd01',)) 419 420 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) 425 426 # Test without offset 427 s.pack_into(writable_buf, 0, test_string) 428 from_buf = writable_buf.tobytes()[:len(test_string)] 429 self.assertEqual(from_buf, test_string) 430 431 # Test with offset. 432 s.pack_into(writable_buf, 10, test_string) 433 from_buf = writable_buf.tobytes()[:len(test_string)+10] 434 self.assertEqual(from_buf, test_string[:10] + test_string) 435 436 # Go beyond boundaries. 437 small_buf = array.array('b', b' '*10) 438 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) 442 443 # Test bogus offset (issue 3694) 444 sb = small_buf 445 self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb, 446 None) 447 448 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) 453 454 # Test without offset. 455 pack_into(writable_buf, 0, test_string) 456 from_buf = writable_buf.tobytes()[:len(test_string)] 457 self.assertEqual(from_buf, test_string) 458 459 # Test with offset. 460 pack_into(writable_buf, 10, test_string) 461 from_buf = writable_buf.tobytes()[:len(test_string)+10] 462 self.assertEqual(from_buf, test_string[:10] + test_string) 463 464 # Go beyond boundaries. 465 small_buf = array.array('b', b' '*10) 466 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) 470 471 def test_unpack_with_buffer(self): 472 # SF bug 1563759: struct.unpack doesn't support buffer protocol objects 473 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) 478 479 def test_bool(self): 480 class ExplodingBool(object): 481 def __bool__(self): 482 raise OSError 483 for prefix in tuple("<>!=")+('',): 484 false = (), [], [], '', 0 485 true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2 486 487 falseFormat = prefix + '?' * len(false) 488 packedFalse = struct.pack(falseFormat, *false) 489 unpackedFalse = struct.unpack(falseFormat, packedFalse) 490 491 trueFormat = prefix + '?' * len(true) 492 packedTrue = struct.pack(trueFormat, *true) 493 unpackedTrue = struct.unpack(trueFormat, packedTrue) 494 495 self.assertEqual(len(true), len(unpackedTrue)) 496 self.assertEqual(len(false), len(unpackedFalse)) 497 498 for t in unpackedFalse: 499 self.assertFalse(t) 500 for t in unpackedTrue: 501 self.assertTrue(t) 502 503 packed = struct.pack(prefix+'?', 1) 504 505 self.assertEqual(len(packed), struct.calcsize(prefix+'?')) 506 507 if len(packed) != 1: 508 self.assertFalse(prefix, msg='encoded bool is not one byte: %r' 509 %packed) 510 511 try: 512 struct.pack(prefix + '?', ExplodingBool()) 513 except OSError: 514 pass 515 else: 516 self.fail("Expected OSError: struct.pack(%r, " 517 "ExplodingBool())" % (prefix + '?')) 518 519 for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']: 520 self.assertTrue(struct.unpack('>?', c)[0]) 521 522 def test_count_overflow(self): 523 hugecount = '{}b'.format(sys.maxsize+1) 524 self.assertRaises(struct.error, struct.calcsize, hugecount) 525 526 hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) 527 self.assertRaises(struct.error, struct.calcsize, hugecount2) 528 529 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') 534 self.assertRaises(struct.error, struct.unpack, '12345', b'') 535 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') 540 self.assertRaises(struct.error, struct.unpack, 'c12345', b'x') 541 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', 549 b'spam and eggs') 550 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 554 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') 560 561 def check_sizeof(self, format_str, number_of_codes): 562 # The size of 'PyStructObject' 563 totalsize = support.calcobjsize('2n3P') 564 # The size taken up by the 'formatcode' dynamic array 565 totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1) 566 support.check_sizeof(self, struct.Struct(format_str), totalsize) 567 568 @support.cpython_only 569 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) 576 self.check_sizeof('100H', 1) 577 self.check_sizeof('187s', 1) 578 self.check_sizeof('20p', 1) 579 self.check_sizeof('0s', 1) 580 self.check_sizeof('0c', 0) 581 582 def test_boundary_error_message(self): 583 regex1 = ( 584 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 ) 588 with self.assertRaisesRegex(struct.error, regex1): 589 struct.pack_into('b', bytearray(1), 5, 1) 590 591 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 599 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) 610 611 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 621 def test_boundary_error_message_with_large_offset(self): 622 # Test overflows cause by large offset and value size (issue 30245) 623 regex1 = ( 624 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 ) 628 with self.assertRaisesRegex(struct.error, regex1): 629 struct.pack_into('<I', bytearray(10), sys.maxsize, 1) 630 631 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 639 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): 644 struct.unpack('b', 0) 645 # Shouldn't crash. 646 self.assertEqual(struct.unpack('b', b'a'), (b'a'[0],)) 647 648 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 656 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) 673 674 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 682class 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 708 def test_uninstantiable(self): 709 iter_unpack_type = type(struct.Struct(">ibcp").iter_unpack(b"")) 710 self.assertRaises(TypeError, iter_unpack_type) 711 712 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 754 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 858 859if __name__ == '__main__': 860 unittest.main() 861