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