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