17db96d56Sopenharmony_cifrom collections import abc 27db96d56Sopenharmony_ciimport array 37db96d56Sopenharmony_ciimport gc 47db96d56Sopenharmony_ciimport math 57db96d56Sopenharmony_ciimport operator 67db96d56Sopenharmony_ciimport unittest 77db96d56Sopenharmony_ciimport struct 87db96d56Sopenharmony_ciimport sys 97db96d56Sopenharmony_ciimport weakref 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_cifrom test import support 127db96d56Sopenharmony_cifrom test.support import import_helper 137db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ciISBIGENDIAN = sys.byteorder == "big" 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciinteger_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' 187db96d56Sopenharmony_cibyteorders = '', '@', '=', '<', '>', '!' 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_cidef iter_integer_formats(byteorders=byteorders): 217db96d56Sopenharmony_ci for code in integer_codes: 227db96d56Sopenharmony_ci for byteorder in byteorders: 237db96d56Sopenharmony_ci if (byteorder not in ('', '@') and code in ('n', 'N')): 247db96d56Sopenharmony_ci continue 257db96d56Sopenharmony_ci yield code, byteorder 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_cidef string_reverse(s): 287db96d56Sopenharmony_ci return s[::-1] 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef bigendian_to_native(value): 317db96d56Sopenharmony_ci if ISBIGENDIAN: 327db96d56Sopenharmony_ci return value 337db96d56Sopenharmony_ci else: 347db96d56Sopenharmony_ci return string_reverse(value) 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciclass StructTest(unittest.TestCase): 377db96d56Sopenharmony_ci def test_isbigendian(self): 387db96d56Sopenharmony_ci self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci def test_consistence(self): 417db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.calcsize, 'Z') 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci sz = struct.calcsize('i') 447db96d56Sopenharmony_ci self.assertEqual(sz * 3, struct.calcsize('iii')) 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci fmt = 'cbxxxxxxhhhhiillffd?' 477db96d56Sopenharmony_ci fmt3 = '3c3b18x12h6i6l6f3d3?' 487db96d56Sopenharmony_ci sz = struct.calcsize(fmt) 497db96d56Sopenharmony_ci sz3 = struct.calcsize(fmt3) 507db96d56Sopenharmony_ci self.assertEqual(sz * 3, sz3) 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, 'iii', 3) 537db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, 'i', 3, 3, 3) 547db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), struct.pack, 'i', 'foo') 557db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), struct.pack, 'P', 'foo') 567db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, 'd', b'flap') 577db96d56Sopenharmony_ci s = struct.pack('ii', 1, 2) 587db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, 'iii', s) 597db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, 'i', s) 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def test_transitiveness(self): 627db96d56Sopenharmony_ci c = b'a' 637db96d56Sopenharmony_ci b = 1 647db96d56Sopenharmony_ci h = 255 657db96d56Sopenharmony_ci i = 65535 667db96d56Sopenharmony_ci l = 65536 677db96d56Sopenharmony_ci f = 3.1415 687db96d56Sopenharmony_ci d = 3.1415 697db96d56Sopenharmony_ci t = True 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci for prefix in ('', '@', '<', '>', '=', '!'): 727db96d56Sopenharmony_ci for format in ('xcbhilfd?', 'xcBHILfd?'): 737db96d56Sopenharmony_ci format = prefix + format 747db96d56Sopenharmony_ci s = struct.pack(format, c, b, h, i, l, f, d, t) 757db96d56Sopenharmony_ci cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s) 767db96d56Sopenharmony_ci self.assertEqual(cp, c) 777db96d56Sopenharmony_ci self.assertEqual(bp, b) 787db96d56Sopenharmony_ci self.assertEqual(hp, h) 797db96d56Sopenharmony_ci self.assertEqual(ip, i) 807db96d56Sopenharmony_ci self.assertEqual(lp, l) 817db96d56Sopenharmony_ci self.assertEqual(int(100 * fp), int(100 * f)) 827db96d56Sopenharmony_ci self.assertEqual(int(100 * dp), int(100 * d)) 837db96d56Sopenharmony_ci self.assertEqual(tp, t) 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci def test_new_features(self): 867db96d56Sopenharmony_ci # Test some of the new features in detail 877db96d56Sopenharmony_ci # (format, argument, big-endian result, little-endian result, asymmetric) 887db96d56Sopenharmony_ci tests = [ 897db96d56Sopenharmony_ci ('c', b'a', b'a', b'a', 0), 907db96d56Sopenharmony_ci ('xc', b'a', b'\0a', b'\0a', 0), 917db96d56Sopenharmony_ci ('cx', b'a', b'a\0', b'a\0', 0), 927db96d56Sopenharmony_ci ('s', b'a', b'a', b'a', 0), 937db96d56Sopenharmony_ci ('0s', b'helloworld', b'', b'', 1), 947db96d56Sopenharmony_ci ('1s', b'helloworld', b'h', b'h', 1), 957db96d56Sopenharmony_ci ('9s', b'helloworld', b'helloworl', b'helloworl', 1), 967db96d56Sopenharmony_ci ('10s', b'helloworld', b'helloworld', b'helloworld', 0), 977db96d56Sopenharmony_ci ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1), 987db96d56Sopenharmony_ci ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1), 997db96d56Sopenharmony_ci ('b', 7, b'\7', b'\7', 0), 1007db96d56Sopenharmony_ci ('b', -7, b'\371', b'\371', 0), 1017db96d56Sopenharmony_ci ('B', 7, b'\7', b'\7', 0), 1027db96d56Sopenharmony_ci ('B', 249, b'\371', b'\371', 0), 1037db96d56Sopenharmony_ci ('h', 700, b'\002\274', b'\274\002', 0), 1047db96d56Sopenharmony_ci ('h', -700, b'\375D', b'D\375', 0), 1057db96d56Sopenharmony_ci ('H', 700, b'\002\274', b'\274\002', 0), 1067db96d56Sopenharmony_ci ('H', 0x10000-700, b'\375D', b'D\375', 0), 1077db96d56Sopenharmony_ci ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 1087db96d56Sopenharmony_ci ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 1097db96d56Sopenharmony_ci ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 1107db96d56Sopenharmony_ci ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 1117db96d56Sopenharmony_ci ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 1127db96d56Sopenharmony_ci ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 1137db96d56Sopenharmony_ci ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0), 1147db96d56Sopenharmony_ci ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), 1157db96d56Sopenharmony_ci ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0), 1167db96d56Sopenharmony_ci ('d', 2.0, b'@\000\000\000\000\000\000\000', 1177db96d56Sopenharmony_ci b'\000\000\000\000\000\000\000@', 0), 1187db96d56Sopenharmony_ci ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0), 1197db96d56Sopenharmony_ci ('d', -2.0, b'\300\000\000\000\000\000\000\000', 1207db96d56Sopenharmony_ci b'\000\000\000\000\000\000\000\300', 0), 1217db96d56Sopenharmony_ci ('?', 0, b'\0', b'\0', 0), 1227db96d56Sopenharmony_ci ('?', 3, b'\1', b'\1', 1), 1237db96d56Sopenharmony_ci ('?', True, b'\1', b'\1', 0), 1247db96d56Sopenharmony_ci ('?', [], b'\0', b'\0', 1), 1257db96d56Sopenharmony_ci ('?', (1,), b'\1', b'\1', 1), 1267db96d56Sopenharmony_ci ] 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci for fmt, arg, big, lil, asy in tests: 1297db96d56Sopenharmony_ci for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), 1307db96d56Sopenharmony_ci ('='+fmt, ISBIGENDIAN and big or lil)]: 1317db96d56Sopenharmony_ci res = struct.pack(xfmt, arg) 1327db96d56Sopenharmony_ci self.assertEqual(res, exp) 1337db96d56Sopenharmony_ci self.assertEqual(struct.calcsize(xfmt), len(res)) 1347db96d56Sopenharmony_ci rev = struct.unpack(xfmt, res)[0] 1357db96d56Sopenharmony_ci if rev != arg: 1367db96d56Sopenharmony_ci self.assertTrue(asy) 1377db96d56Sopenharmony_ci 1387db96d56Sopenharmony_ci def test_calcsize(self): 1397db96d56Sopenharmony_ci expected_size = { 1407db96d56Sopenharmony_ci 'b': 1, 'B': 1, 1417db96d56Sopenharmony_ci 'h': 2, 'H': 2, 1427db96d56Sopenharmony_ci 'i': 4, 'I': 4, 1437db96d56Sopenharmony_ci 'l': 4, 'L': 4, 1447db96d56Sopenharmony_ci 'q': 8, 'Q': 8, 1457db96d56Sopenharmony_ci } 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci # standard integer sizes 1487db96d56Sopenharmony_ci for code, byteorder in iter_integer_formats(('=', '<', '>', '!')): 1497db96d56Sopenharmony_ci format = byteorder+code 1507db96d56Sopenharmony_ci size = struct.calcsize(format) 1517db96d56Sopenharmony_ci self.assertEqual(size, expected_size[code]) 1527db96d56Sopenharmony_ci 1537db96d56Sopenharmony_ci # native integer sizes 1547db96d56Sopenharmony_ci native_pairs = 'bB', 'hH', 'iI', 'lL', 'nN', 'qQ' 1557db96d56Sopenharmony_ci for format_pair in native_pairs: 1567db96d56Sopenharmony_ci for byteorder in '', '@': 1577db96d56Sopenharmony_ci signed_size = struct.calcsize(byteorder + format_pair[0]) 1587db96d56Sopenharmony_ci unsigned_size = struct.calcsize(byteorder + format_pair[1]) 1597db96d56Sopenharmony_ci self.assertEqual(signed_size, unsigned_size) 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci # bounds for native integer sizes 1627db96d56Sopenharmony_ci self.assertEqual(struct.calcsize('b'), 1) 1637db96d56Sopenharmony_ci self.assertLessEqual(2, struct.calcsize('h')) 1647db96d56Sopenharmony_ci self.assertLessEqual(4, struct.calcsize('l')) 1657db96d56Sopenharmony_ci self.assertLessEqual(struct.calcsize('h'), struct.calcsize('i')) 1667db96d56Sopenharmony_ci self.assertLessEqual(struct.calcsize('i'), struct.calcsize('l')) 1677db96d56Sopenharmony_ci self.assertLessEqual(8, struct.calcsize('q')) 1687db96d56Sopenharmony_ci self.assertLessEqual(struct.calcsize('l'), struct.calcsize('q')) 1697db96d56Sopenharmony_ci self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i')) 1707db96d56Sopenharmony_ci self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P')) 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci def test_integers(self): 1737db96d56Sopenharmony_ci # Integer tests (bBhHiIlLqQnN). 1747db96d56Sopenharmony_ci import binascii 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci class IntTester(unittest.TestCase): 1777db96d56Sopenharmony_ci def __init__(self, format): 1787db96d56Sopenharmony_ci super(IntTester, self).__init__(methodName='test_one') 1797db96d56Sopenharmony_ci self.format = format 1807db96d56Sopenharmony_ci self.code = format[-1] 1817db96d56Sopenharmony_ci self.byteorder = format[:-1] 1827db96d56Sopenharmony_ci if not self.byteorder in byteorders: 1837db96d56Sopenharmony_ci raise ValueError("unrecognized packing byteorder: %s" % 1847db96d56Sopenharmony_ci self.byteorder) 1857db96d56Sopenharmony_ci self.bytesize = struct.calcsize(format) 1867db96d56Sopenharmony_ci self.bitsize = self.bytesize * 8 1877db96d56Sopenharmony_ci if self.code in tuple('bhilqn'): 1887db96d56Sopenharmony_ci self.signed = True 1897db96d56Sopenharmony_ci self.min_value = -(2**(self.bitsize-1)) 1907db96d56Sopenharmony_ci self.max_value = 2**(self.bitsize-1) - 1 1917db96d56Sopenharmony_ci elif self.code in tuple('BHILQN'): 1927db96d56Sopenharmony_ci self.signed = False 1937db96d56Sopenharmony_ci self.min_value = 0 1947db96d56Sopenharmony_ci self.max_value = 2**self.bitsize - 1 1957db96d56Sopenharmony_ci else: 1967db96d56Sopenharmony_ci raise ValueError("unrecognized format code: %s" % 1977db96d56Sopenharmony_ci self.code) 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci def test_one(self, x, pack=struct.pack, 2007db96d56Sopenharmony_ci unpack=struct.unpack, 2017db96d56Sopenharmony_ci unhexlify=binascii.unhexlify): 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci format = self.format 2047db96d56Sopenharmony_ci if self.min_value <= x <= self.max_value: 2057db96d56Sopenharmony_ci expected = x 2067db96d56Sopenharmony_ci if self.signed and x < 0: 2077db96d56Sopenharmony_ci expected += 1 << self.bitsize 2087db96d56Sopenharmony_ci self.assertGreaterEqual(expected, 0) 2097db96d56Sopenharmony_ci expected = '%x' % expected 2107db96d56Sopenharmony_ci if len(expected) & 1: 2117db96d56Sopenharmony_ci expected = "0" + expected 2127db96d56Sopenharmony_ci expected = expected.encode('ascii') 2137db96d56Sopenharmony_ci expected = unhexlify(expected) 2147db96d56Sopenharmony_ci expected = (b"\x00" * (self.bytesize - len(expected)) + 2157db96d56Sopenharmony_ci expected) 2167db96d56Sopenharmony_ci if (self.byteorder == '<' or 2177db96d56Sopenharmony_ci self.byteorder in ('', '@', '=') and not ISBIGENDIAN): 2187db96d56Sopenharmony_ci expected = string_reverse(expected) 2197db96d56Sopenharmony_ci self.assertEqual(len(expected), self.bytesize) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci # Pack work? 2227db96d56Sopenharmony_ci got = pack(format, x) 2237db96d56Sopenharmony_ci self.assertEqual(got, expected) 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci # Unpack work? 2267db96d56Sopenharmony_ci retrieved = unpack(format, got)[0] 2277db96d56Sopenharmony_ci self.assertEqual(x, retrieved) 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci # Adding any byte should cause a "too big" error. 2307db96d56Sopenharmony_ci self.assertRaises((struct.error, TypeError), unpack, format, 2317db96d56Sopenharmony_ci b'\x01' + got) 2327db96d56Sopenharmony_ci else: 2337db96d56Sopenharmony_ci # x is out of range -- verify pack realizes that. 2347db96d56Sopenharmony_ci self.assertRaises((OverflowError, ValueError, struct.error), 2357db96d56Sopenharmony_ci pack, format, x) 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_ci def run(self): 2387db96d56Sopenharmony_ci from random import randrange 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_ci # Create all interesting powers of 2. 2417db96d56Sopenharmony_ci values = [] 2427db96d56Sopenharmony_ci for exp in range(self.bitsize + 3): 2437db96d56Sopenharmony_ci values.append(1 << exp) 2447db96d56Sopenharmony_ci 2457db96d56Sopenharmony_ci # Add some random values. 2467db96d56Sopenharmony_ci for i in range(self.bitsize): 2477db96d56Sopenharmony_ci val = 0 2487db96d56Sopenharmony_ci for j in range(self.bytesize): 2497db96d56Sopenharmony_ci val = (val << 8) | randrange(256) 2507db96d56Sopenharmony_ci values.append(val) 2517db96d56Sopenharmony_ci 2527db96d56Sopenharmony_ci # Values absorbed from other tests 2537db96d56Sopenharmony_ci values.extend([300, 700000, sys.maxsize*4]) 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci # Try all those, and their negations, and +-1 from 2567db96d56Sopenharmony_ci # them. Note that this tests all power-of-2 2577db96d56Sopenharmony_ci # boundaries in range, and a few out of range, plus 2587db96d56Sopenharmony_ci # +-(2**n +- 1). 2597db96d56Sopenharmony_ci for base in values: 2607db96d56Sopenharmony_ci for val in -base, base: 2617db96d56Sopenharmony_ci for incr in -1, 0, 1: 2627db96d56Sopenharmony_ci x = val + incr 2637db96d56Sopenharmony_ci self.test_one(x) 2647db96d56Sopenharmony_ci 2657db96d56Sopenharmony_ci # Some error cases. 2667db96d56Sopenharmony_ci class NotAnInt: 2677db96d56Sopenharmony_ci def __int__(self): 2687db96d56Sopenharmony_ci return 42 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci # Objects with an '__index__' method should be allowed 2717db96d56Sopenharmony_ci # to pack as integers. That is assuming the implemented 2727db96d56Sopenharmony_ci # '__index__' method returns an 'int'. 2737db96d56Sopenharmony_ci class Indexable(object): 2747db96d56Sopenharmony_ci def __init__(self, value): 2757db96d56Sopenharmony_ci self._value = value 2767db96d56Sopenharmony_ci 2777db96d56Sopenharmony_ci def __index__(self): 2787db96d56Sopenharmony_ci return self._value 2797db96d56Sopenharmony_ci 2807db96d56Sopenharmony_ci # If the '__index__' method raises a type error, then 2817db96d56Sopenharmony_ci # '__int__' should be used with a deprecation warning. 2827db96d56Sopenharmony_ci class BadIndex(object): 2837db96d56Sopenharmony_ci def __index__(self): 2847db96d56Sopenharmony_ci raise TypeError 2857db96d56Sopenharmony_ci 2867db96d56Sopenharmony_ci def __int__(self): 2877db96d56Sopenharmony_ci return 42 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 2907db96d56Sopenharmony_ci struct.pack, self.format, 2917db96d56Sopenharmony_ci "a string") 2927db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 2937db96d56Sopenharmony_ci struct.pack, self.format, 2947db96d56Sopenharmony_ci randrange) 2957db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 2967db96d56Sopenharmony_ci struct.pack, self.format, 2977db96d56Sopenharmony_ci 3+42j) 2987db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 2997db96d56Sopenharmony_ci struct.pack, self.format, 3007db96d56Sopenharmony_ci NotAnInt()) 3017db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 3027db96d56Sopenharmony_ci struct.pack, self.format, 3037db96d56Sopenharmony_ci BadIndex()) 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_ci # Check for legitimate values from '__index__'. 3067db96d56Sopenharmony_ci for obj in (Indexable(0), Indexable(10), Indexable(17), 3077db96d56Sopenharmony_ci Indexable(42), Indexable(100), Indexable(127)): 3087db96d56Sopenharmony_ci try: 3097db96d56Sopenharmony_ci struct.pack(format, obj) 3107db96d56Sopenharmony_ci except: 3117db96d56Sopenharmony_ci self.fail("integer code pack failed on object " 3127db96d56Sopenharmony_ci "with '__index__' method") 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci # Check for bogus values from '__index__'. 3157db96d56Sopenharmony_ci for obj in (Indexable(b'a'), Indexable('b'), Indexable(None), 3167db96d56Sopenharmony_ci Indexable({'a': 1}), Indexable([1, 2, 3])): 3177db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), 3187db96d56Sopenharmony_ci struct.pack, self.format, 3197db96d56Sopenharmony_ci obj) 3207db96d56Sopenharmony_ci 3217db96d56Sopenharmony_ci for code, byteorder in iter_integer_formats(): 3227db96d56Sopenharmony_ci format = byteorder+code 3237db96d56Sopenharmony_ci t = IntTester(format) 3247db96d56Sopenharmony_ci t.run() 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci def test_nN_code(self): 3277db96d56Sopenharmony_ci # n and N don't exist in standard sizes 3287db96d56Sopenharmony_ci def assertStructError(func, *args, **kwargs): 3297db96d56Sopenharmony_ci with self.assertRaises(struct.error) as cm: 3307db96d56Sopenharmony_ci func(*args, **kwargs) 3317db96d56Sopenharmony_ci self.assertIn("bad char in struct format", str(cm.exception)) 3327db96d56Sopenharmony_ci for code in 'nN': 3337db96d56Sopenharmony_ci for byteorder in ('=', '<', '>', '!'): 3347db96d56Sopenharmony_ci format = byteorder+code 3357db96d56Sopenharmony_ci assertStructError(struct.calcsize, format) 3367db96d56Sopenharmony_ci assertStructError(struct.pack, format, 0) 3377db96d56Sopenharmony_ci assertStructError(struct.unpack, format, b"") 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci def test_p_code(self): 3407db96d56Sopenharmony_ci # Test p ("Pascal string") code. 3417db96d56Sopenharmony_ci for code, input, expected, expectedback in [ 3427db96d56Sopenharmony_ci ('p', b'abc', b'\x00', b''), 3437db96d56Sopenharmony_ci ('1p', b'abc', b'\x00', b''), 3447db96d56Sopenharmony_ci ('2p', b'abc', b'\x01a', b'a'), 3457db96d56Sopenharmony_ci ('3p', b'abc', b'\x02ab', b'ab'), 3467db96d56Sopenharmony_ci ('4p', b'abc', b'\x03abc', b'abc'), 3477db96d56Sopenharmony_ci ('5p', b'abc', b'\x03abc\x00', b'abc'), 3487db96d56Sopenharmony_ci ('6p', b'abc', b'\x03abc\x00\x00', b'abc'), 3497db96d56Sopenharmony_ci ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]: 3507db96d56Sopenharmony_ci got = struct.pack(code, input) 3517db96d56Sopenharmony_ci self.assertEqual(got, expected) 3527db96d56Sopenharmony_ci (got,) = struct.unpack(code, got) 3537db96d56Sopenharmony_ci self.assertEqual(got, expectedback) 3547db96d56Sopenharmony_ci 3557db96d56Sopenharmony_ci def test_705836(self): 3567db96d56Sopenharmony_ci # SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry 3577db96d56Sopenharmony_ci # from the low-order discarded bits could propagate into the exponent 3587db96d56Sopenharmony_ci # field, causing the result to be wrong by a factor of 2. 3597db96d56Sopenharmony_ci for base in range(1, 33): 3607db96d56Sopenharmony_ci # smaller <- largest representable float less than base. 3617db96d56Sopenharmony_ci delta = 0.5 3627db96d56Sopenharmony_ci while base - delta / 2.0 != base: 3637db96d56Sopenharmony_ci delta /= 2.0 3647db96d56Sopenharmony_ci smaller = base - delta 3657db96d56Sopenharmony_ci # Packing this rounds away a solid string of trailing 1 bits. 3667db96d56Sopenharmony_ci packed = struct.pack("<f", smaller) 3677db96d56Sopenharmony_ci unpacked = struct.unpack("<f", packed)[0] 3687db96d56Sopenharmony_ci # This failed at base = 2, 4, and 32, with unpacked = 1, 2, and 3697db96d56Sopenharmony_ci # 16, respectively. 3707db96d56Sopenharmony_ci self.assertEqual(base, unpacked) 3717db96d56Sopenharmony_ci bigpacked = struct.pack(">f", smaller) 3727db96d56Sopenharmony_ci self.assertEqual(bigpacked, string_reverse(packed)) 3737db96d56Sopenharmony_ci unpacked = struct.unpack(">f", bigpacked)[0] 3747db96d56Sopenharmony_ci self.assertEqual(base, unpacked) 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci # Largest finite IEEE single. 3777db96d56Sopenharmony_ci big = (1 << 24) - 1 3787db96d56Sopenharmony_ci big = math.ldexp(big, 127 - 23) 3797db96d56Sopenharmony_ci packed = struct.pack(">f", big) 3807db96d56Sopenharmony_ci unpacked = struct.unpack(">f", packed)[0] 3817db96d56Sopenharmony_ci self.assertEqual(big, unpacked) 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci # The same, but tack on a 1 bit so it rounds up to infinity. 3847db96d56Sopenharmony_ci big = (1 << 25) - 1 3857db96d56Sopenharmony_ci big = math.ldexp(big, 127 - 24) 3867db96d56Sopenharmony_ci self.assertRaises(OverflowError, struct.pack, ">f", big) 3877db96d56Sopenharmony_ci 3887db96d56Sopenharmony_ci def test_1530559(self): 3897db96d56Sopenharmony_ci for code, byteorder in iter_integer_formats(): 3907db96d56Sopenharmony_ci format = byteorder + code 3917db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, format, 1.0) 3927db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, format, 1.5) 3937db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, 'P', 1.0) 3947db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, 'P', 1.5) 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ci def test_unpack_from(self): 3977db96d56Sopenharmony_ci test_string = b'abcd01234' 3987db96d56Sopenharmony_ci fmt = '4s' 3997db96d56Sopenharmony_ci s = struct.Struct(fmt) 4007db96d56Sopenharmony_ci for cls in (bytes, bytearray): 4017db96d56Sopenharmony_ci data = cls(test_string) 4027db96d56Sopenharmony_ci self.assertEqual(s.unpack_from(data), (b'abcd',)) 4037db96d56Sopenharmony_ci self.assertEqual(s.unpack_from(data, 2), (b'cd01',)) 4047db96d56Sopenharmony_ci self.assertEqual(s.unpack_from(data, 4), (b'0123',)) 4057db96d56Sopenharmony_ci for i in range(6): 4067db96d56Sopenharmony_ci self.assertEqual(s.unpack_from(data, i), (data[i:i+4],)) 4077db96d56Sopenharmony_ci for i in range(6, len(test_string) + 1): 4087db96d56Sopenharmony_ci self.assertRaises(struct.error, s.unpack_from, data, i) 4097db96d56Sopenharmony_ci for cls in (bytes, bytearray): 4107db96d56Sopenharmony_ci data = cls(test_string) 4117db96d56Sopenharmony_ci self.assertEqual(struct.unpack_from(fmt, data), (b'abcd',)) 4127db96d56Sopenharmony_ci self.assertEqual(struct.unpack_from(fmt, data, 2), (b'cd01',)) 4137db96d56Sopenharmony_ci self.assertEqual(struct.unpack_from(fmt, data, 4), (b'0123',)) 4147db96d56Sopenharmony_ci for i in range(6): 4157db96d56Sopenharmony_ci self.assertEqual(struct.unpack_from(fmt, data, i), (data[i:i+4],)) 4167db96d56Sopenharmony_ci for i in range(6, len(test_string) + 1): 4177db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack_from, fmt, data, i) 4187db96d56Sopenharmony_ci 4197db96d56Sopenharmony_ci # keyword arguments 4207db96d56Sopenharmony_ci self.assertEqual(s.unpack_from(buffer=test_string, offset=2), 4217db96d56Sopenharmony_ci (b'cd01',)) 4227db96d56Sopenharmony_ci 4237db96d56Sopenharmony_ci def test_pack_into(self): 4247db96d56Sopenharmony_ci test_string = b'Reykjavik rocks, eow!' 4257db96d56Sopenharmony_ci writable_buf = array.array('b', b' '*100) 4267db96d56Sopenharmony_ci fmt = '21s' 4277db96d56Sopenharmony_ci s = struct.Struct(fmt) 4287db96d56Sopenharmony_ci 4297db96d56Sopenharmony_ci # Test without offset 4307db96d56Sopenharmony_ci s.pack_into(writable_buf, 0, test_string) 4317db96d56Sopenharmony_ci from_buf = writable_buf.tobytes()[:len(test_string)] 4327db96d56Sopenharmony_ci self.assertEqual(from_buf, test_string) 4337db96d56Sopenharmony_ci 4347db96d56Sopenharmony_ci # Test with offset. 4357db96d56Sopenharmony_ci s.pack_into(writable_buf, 10, test_string) 4367db96d56Sopenharmony_ci from_buf = writable_buf.tobytes()[:len(test_string)+10] 4377db96d56Sopenharmony_ci self.assertEqual(from_buf, test_string[:10] + test_string) 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ci # Go beyond boundaries. 4407db96d56Sopenharmony_ci small_buf = array.array('b', b' '*10) 4417db96d56Sopenharmony_ci self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0, 4427db96d56Sopenharmony_ci test_string) 4437db96d56Sopenharmony_ci self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2, 4447db96d56Sopenharmony_ci test_string) 4457db96d56Sopenharmony_ci 4467db96d56Sopenharmony_ci # Test bogus offset (issue 3694) 4477db96d56Sopenharmony_ci sb = small_buf 4487db96d56Sopenharmony_ci self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb, 4497db96d56Sopenharmony_ci None) 4507db96d56Sopenharmony_ci 4517db96d56Sopenharmony_ci def test_pack_into_fn(self): 4527db96d56Sopenharmony_ci test_string = b'Reykjavik rocks, eow!' 4537db96d56Sopenharmony_ci writable_buf = array.array('b', b' '*100) 4547db96d56Sopenharmony_ci fmt = '21s' 4557db96d56Sopenharmony_ci pack_into = lambda *args: struct.pack_into(fmt, *args) 4567db96d56Sopenharmony_ci 4577db96d56Sopenharmony_ci # Test without offset. 4587db96d56Sopenharmony_ci pack_into(writable_buf, 0, test_string) 4597db96d56Sopenharmony_ci from_buf = writable_buf.tobytes()[:len(test_string)] 4607db96d56Sopenharmony_ci self.assertEqual(from_buf, test_string) 4617db96d56Sopenharmony_ci 4627db96d56Sopenharmony_ci # Test with offset. 4637db96d56Sopenharmony_ci pack_into(writable_buf, 10, test_string) 4647db96d56Sopenharmony_ci from_buf = writable_buf.tobytes()[:len(test_string)+10] 4657db96d56Sopenharmony_ci self.assertEqual(from_buf, test_string[:10] + test_string) 4667db96d56Sopenharmony_ci 4677db96d56Sopenharmony_ci # Go beyond boundaries. 4687db96d56Sopenharmony_ci small_buf = array.array('b', b' '*10) 4697db96d56Sopenharmony_ci self.assertRaises((ValueError, struct.error), pack_into, small_buf, 0, 4707db96d56Sopenharmony_ci test_string) 4717db96d56Sopenharmony_ci self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2, 4727db96d56Sopenharmony_ci test_string) 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_ci def test_unpack_with_buffer(self): 4757db96d56Sopenharmony_ci # SF bug 1563759: struct.unpack doesn't support buffer protocol objects 4767db96d56Sopenharmony_ci data1 = array.array('B', b'\x12\x34\x56\x78') 4777db96d56Sopenharmony_ci data2 = memoryview(b'\x12\x34\x56\x78') # XXX b'......XXXX......', 6, 4 4787db96d56Sopenharmony_ci for data in [data1, data2]: 4797db96d56Sopenharmony_ci value, = struct.unpack('>I', data) 4807db96d56Sopenharmony_ci self.assertEqual(value, 0x12345678) 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci def test_bool(self): 4837db96d56Sopenharmony_ci class ExplodingBool(object): 4847db96d56Sopenharmony_ci def __bool__(self): 4857db96d56Sopenharmony_ci raise OSError 4867db96d56Sopenharmony_ci for prefix in tuple("<>!=")+('',): 4877db96d56Sopenharmony_ci false = (), [], [], '', 0 4887db96d56Sopenharmony_ci true = [1], 'test', 5, -1, 0xffffffff+1, 0xffffffff/2 4897db96d56Sopenharmony_ci 4907db96d56Sopenharmony_ci falseFormat = prefix + '?' * len(false) 4917db96d56Sopenharmony_ci packedFalse = struct.pack(falseFormat, *false) 4927db96d56Sopenharmony_ci unpackedFalse = struct.unpack(falseFormat, packedFalse) 4937db96d56Sopenharmony_ci 4947db96d56Sopenharmony_ci trueFormat = prefix + '?' * len(true) 4957db96d56Sopenharmony_ci packedTrue = struct.pack(trueFormat, *true) 4967db96d56Sopenharmony_ci unpackedTrue = struct.unpack(trueFormat, packedTrue) 4977db96d56Sopenharmony_ci 4987db96d56Sopenharmony_ci self.assertEqual(len(true), len(unpackedTrue)) 4997db96d56Sopenharmony_ci self.assertEqual(len(false), len(unpackedFalse)) 5007db96d56Sopenharmony_ci 5017db96d56Sopenharmony_ci for t in unpackedFalse: 5027db96d56Sopenharmony_ci self.assertFalse(t) 5037db96d56Sopenharmony_ci for t in unpackedTrue: 5047db96d56Sopenharmony_ci self.assertTrue(t) 5057db96d56Sopenharmony_ci 5067db96d56Sopenharmony_ci packed = struct.pack(prefix+'?', 1) 5077db96d56Sopenharmony_ci 5087db96d56Sopenharmony_ci self.assertEqual(len(packed), struct.calcsize(prefix+'?')) 5097db96d56Sopenharmony_ci 5107db96d56Sopenharmony_ci if len(packed) != 1: 5117db96d56Sopenharmony_ci self.assertFalse(prefix, msg='encoded bool is not one byte: %r' 5127db96d56Sopenharmony_ci %packed) 5137db96d56Sopenharmony_ci 5147db96d56Sopenharmony_ci try: 5157db96d56Sopenharmony_ci struct.pack(prefix + '?', ExplodingBool()) 5167db96d56Sopenharmony_ci except OSError: 5177db96d56Sopenharmony_ci pass 5187db96d56Sopenharmony_ci else: 5197db96d56Sopenharmony_ci self.fail("Expected OSError: struct.pack(%r, " 5207db96d56Sopenharmony_ci "ExplodingBool())" % (prefix + '?')) 5217db96d56Sopenharmony_ci 5227db96d56Sopenharmony_ci for c in [b'\x01', b'\x7f', b'\xff', b'\x0f', b'\xf0']: 5237db96d56Sopenharmony_ci self.assertTrue(struct.unpack('>?', c)[0]) 5247db96d56Sopenharmony_ci 5257db96d56Sopenharmony_ci def test_count_overflow(self): 5267db96d56Sopenharmony_ci hugecount = '{}b'.format(sys.maxsize+1) 5277db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.calcsize, hugecount) 5287db96d56Sopenharmony_ci 5297db96d56Sopenharmony_ci hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) 5307db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.calcsize, hugecount2) 5317db96d56Sopenharmony_ci 5327db96d56Sopenharmony_ci def test_trailing_counter(self): 5337db96d56Sopenharmony_ci store = array.array('b', b' '*100) 5347db96d56Sopenharmony_ci 5357db96d56Sopenharmony_ci # format lists containing only count spec should result in an error 5367db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, '12345') 5377db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, '12345', b'') 5387db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack_into, '12345', store, 0) 5397db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0) 5407db96d56Sopenharmony_ci 5417db96d56Sopenharmony_ci # Format lists with trailing count spec should result in an error 5427db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, 'c12345', 'x') 5437db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, 'c12345', b'x') 5447db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0, 5457db96d56Sopenharmony_ci 'x') 5467db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack_from, 'c12345', store, 5477db96d56Sopenharmony_ci 0) 5487db96d56Sopenharmony_ci 5497db96d56Sopenharmony_ci # Mixed format tests 5507db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs') 5517db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack, '14s42', 5527db96d56Sopenharmony_ci b'spam and eggs') 5537db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0, 5547db96d56Sopenharmony_ci 'spam and eggs') 5557db96d56Sopenharmony_ci self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0) 5567db96d56Sopenharmony_ci 5577db96d56Sopenharmony_ci def test_Struct_reinitialization(self): 5587db96d56Sopenharmony_ci # Issue 9422: there was a memory leak when reinitializing a 5597db96d56Sopenharmony_ci # Struct instance. This test can be used to detect the leak 5607db96d56Sopenharmony_ci # when running with regrtest -L. 5617db96d56Sopenharmony_ci s = struct.Struct('i') 5627db96d56Sopenharmony_ci s.__init__('ii') 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci def check_sizeof(self, format_str, number_of_codes): 5657db96d56Sopenharmony_ci # The size of 'PyStructObject' 5667db96d56Sopenharmony_ci totalsize = support.calcobjsize('2n3P') 5677db96d56Sopenharmony_ci # The size taken up by the 'formatcode' dynamic array 5687db96d56Sopenharmony_ci totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1) 5697db96d56Sopenharmony_ci support.check_sizeof(self, struct.Struct(format_str), totalsize) 5707db96d56Sopenharmony_ci 5717db96d56Sopenharmony_ci @support.cpython_only 5727db96d56Sopenharmony_ci def test__sizeof__(self): 5737db96d56Sopenharmony_ci for code in integer_codes: 5747db96d56Sopenharmony_ci self.check_sizeof(code, 1) 5757db96d56Sopenharmony_ci self.check_sizeof('BHILfdspP', 9) 5767db96d56Sopenharmony_ci self.check_sizeof('B' * 1234, 1234) 5777db96d56Sopenharmony_ci self.check_sizeof('fd', 2) 5787db96d56Sopenharmony_ci self.check_sizeof('xxxxxxxxxxxxxx', 0) 5797db96d56Sopenharmony_ci self.check_sizeof('100H', 1) 5807db96d56Sopenharmony_ci self.check_sizeof('187s', 1) 5817db96d56Sopenharmony_ci self.check_sizeof('20p', 1) 5827db96d56Sopenharmony_ci self.check_sizeof('0s', 1) 5837db96d56Sopenharmony_ci self.check_sizeof('0c', 0) 5847db96d56Sopenharmony_ci 5857db96d56Sopenharmony_ci def test_boundary_error_message(self): 5867db96d56Sopenharmony_ci regex1 = ( 5877db96d56Sopenharmony_ci r'pack_into requires a buffer of at least 6 ' 5887db96d56Sopenharmony_ci r'bytes for packing 1 bytes at offset 5 ' 5897db96d56Sopenharmony_ci r'\(actual buffer size is 1\)' 5907db96d56Sopenharmony_ci ) 5917db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, regex1): 5927db96d56Sopenharmony_ci struct.pack_into('b', bytearray(1), 5, 1) 5937db96d56Sopenharmony_ci 5947db96d56Sopenharmony_ci regex2 = ( 5957db96d56Sopenharmony_ci r'unpack_from requires a buffer of at least 6 ' 5967db96d56Sopenharmony_ci r'bytes for unpacking 1 bytes at offset 5 ' 5977db96d56Sopenharmony_ci r'\(actual buffer size is 1\)' 5987db96d56Sopenharmony_ci ) 5997db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, regex2): 6007db96d56Sopenharmony_ci struct.unpack_from('b', bytearray(1), 5) 6017db96d56Sopenharmony_ci 6027db96d56Sopenharmony_ci def test_boundary_error_message_with_negative_offset(self): 6037db96d56Sopenharmony_ci byte_list = bytearray(10) 6047db96d56Sopenharmony_ci with self.assertRaisesRegex( 6057db96d56Sopenharmony_ci struct.error, 6067db96d56Sopenharmony_ci r'no space to pack 4 bytes at offset -2'): 6077db96d56Sopenharmony_ci struct.pack_into('<I', byte_list, -2, 123) 6087db96d56Sopenharmony_ci 6097db96d56Sopenharmony_ci with self.assertRaisesRegex( 6107db96d56Sopenharmony_ci struct.error, 6117db96d56Sopenharmony_ci 'offset -11 out of range for 10-byte buffer'): 6127db96d56Sopenharmony_ci struct.pack_into('<B', byte_list, -11, 123) 6137db96d56Sopenharmony_ci 6147db96d56Sopenharmony_ci with self.assertRaisesRegex( 6157db96d56Sopenharmony_ci struct.error, 6167db96d56Sopenharmony_ci r'not enough data to unpack 4 bytes at offset -2'): 6177db96d56Sopenharmony_ci struct.unpack_from('<I', byte_list, -2) 6187db96d56Sopenharmony_ci 6197db96d56Sopenharmony_ci with self.assertRaisesRegex( 6207db96d56Sopenharmony_ci struct.error, 6217db96d56Sopenharmony_ci "offset -11 out of range for 10-byte buffer"): 6227db96d56Sopenharmony_ci struct.unpack_from('<B', byte_list, -11) 6237db96d56Sopenharmony_ci 6247db96d56Sopenharmony_ci def test_boundary_error_message_with_large_offset(self): 6257db96d56Sopenharmony_ci # Test overflows cause by large offset and value size (issue 30245) 6267db96d56Sopenharmony_ci regex1 = ( 6277db96d56Sopenharmony_ci r'pack_into requires a buffer of at least ' + str(sys.maxsize + 4) + 6287db96d56Sopenharmony_ci r' bytes for packing 4 bytes at offset ' + str(sys.maxsize) + 6297db96d56Sopenharmony_ci r' \(actual buffer size is 10\)' 6307db96d56Sopenharmony_ci ) 6317db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, regex1): 6327db96d56Sopenharmony_ci struct.pack_into('<I', bytearray(10), sys.maxsize, 1) 6337db96d56Sopenharmony_ci 6347db96d56Sopenharmony_ci regex2 = ( 6357db96d56Sopenharmony_ci r'unpack_from requires a buffer of at least ' + str(sys.maxsize + 4) + 6367db96d56Sopenharmony_ci r' bytes for unpacking 4 bytes at offset ' + str(sys.maxsize) + 6377db96d56Sopenharmony_ci r' \(actual buffer size is 10\)' 6387db96d56Sopenharmony_ci ) 6397db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, regex2): 6407db96d56Sopenharmony_ci struct.unpack_from('<I', bytearray(10), sys.maxsize) 6417db96d56Sopenharmony_ci 6427db96d56Sopenharmony_ci def test_issue29802(self): 6437db96d56Sopenharmony_ci # When the second argument of struct.unpack() was of wrong type 6447db96d56Sopenharmony_ci # the Struct object was decrefed twice and the reference to 6457db96d56Sopenharmony_ci # deallocated object was left in a cache. 6467db96d56Sopenharmony_ci with self.assertRaises(TypeError): 6477db96d56Sopenharmony_ci struct.unpack('b', 0) 6487db96d56Sopenharmony_ci # Shouldn't crash. 6497db96d56Sopenharmony_ci self.assertEqual(struct.unpack('b', b'a'), (b'a'[0],)) 6507db96d56Sopenharmony_ci 6517db96d56Sopenharmony_ci def test_format_attr(self): 6527db96d56Sopenharmony_ci s = struct.Struct('=i2H') 6537db96d56Sopenharmony_ci self.assertEqual(s.format, '=i2H') 6547db96d56Sopenharmony_ci 6557db96d56Sopenharmony_ci # use a bytes string 6567db96d56Sopenharmony_ci s2 = struct.Struct(s.format.encode()) 6577db96d56Sopenharmony_ci self.assertEqual(s2.format, s.format) 6587db96d56Sopenharmony_ci 6597db96d56Sopenharmony_ci def test_struct_cleans_up_at_runtime_shutdown(self): 6607db96d56Sopenharmony_ci code = """if 1: 6617db96d56Sopenharmony_ci import struct 6627db96d56Sopenharmony_ci 6637db96d56Sopenharmony_ci class C: 6647db96d56Sopenharmony_ci def __init__(self): 6657db96d56Sopenharmony_ci self.pack = struct.pack 6667db96d56Sopenharmony_ci def __del__(self): 6677db96d56Sopenharmony_ci self.pack('I', -42) 6687db96d56Sopenharmony_ci 6697db96d56Sopenharmony_ci struct.x = C() 6707db96d56Sopenharmony_ci """ 6717db96d56Sopenharmony_ci rc, stdout, stderr = assert_python_ok("-c", code) 6727db96d56Sopenharmony_ci self.assertEqual(rc, 0) 6737db96d56Sopenharmony_ci self.assertEqual(stdout.rstrip(), b"") 6747db96d56Sopenharmony_ci self.assertIn(b"Exception ignored in:", stderr) 6757db96d56Sopenharmony_ci self.assertIn(b"C.__del__", stderr) 6767db96d56Sopenharmony_ci 6777db96d56Sopenharmony_ci def test__struct_reference_cycle_cleaned_up(self): 6787db96d56Sopenharmony_ci # Regression test for python/cpython#94207. 6797db96d56Sopenharmony_ci 6807db96d56Sopenharmony_ci # When we create a new struct module, trigger use of its cache, 6817db96d56Sopenharmony_ci # and then delete it ... 6827db96d56Sopenharmony_ci _struct_module = import_helper.import_fresh_module("_struct") 6837db96d56Sopenharmony_ci module_ref = weakref.ref(_struct_module) 6847db96d56Sopenharmony_ci _struct_module.calcsize("b") 6857db96d56Sopenharmony_ci del _struct_module 6867db96d56Sopenharmony_ci 6877db96d56Sopenharmony_ci # Then the module should have been garbage collected. 6887db96d56Sopenharmony_ci gc.collect() 6897db96d56Sopenharmony_ci self.assertIsNone( 6907db96d56Sopenharmony_ci module_ref(), "_struct module was not garbage collected") 6917db96d56Sopenharmony_ci 6927db96d56Sopenharmony_ci @support.cpython_only 6937db96d56Sopenharmony_ci def test__struct_types_immutable(self): 6947db96d56Sopenharmony_ci # See https://github.com/python/cpython/issues/94254 6957db96d56Sopenharmony_ci 6967db96d56Sopenharmony_ci Struct = struct.Struct 6977db96d56Sopenharmony_ci unpack_iterator = type(struct.iter_unpack("b", b'x')) 6987db96d56Sopenharmony_ci for cls in (Struct, unpack_iterator): 6997db96d56Sopenharmony_ci with self.subTest(cls=cls): 7007db96d56Sopenharmony_ci with self.assertRaises(TypeError): 7017db96d56Sopenharmony_ci cls.x = 1 7027db96d56Sopenharmony_ci 7037db96d56Sopenharmony_ci 7047db96d56Sopenharmony_ci def test_issue35714(self): 7057db96d56Sopenharmony_ci # Embedded null characters should not be allowed in format strings. 7067db96d56Sopenharmony_ci for s in '\0', '2\0i', b'\0': 7077db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, 7087db96d56Sopenharmony_ci 'embedded null character'): 7097db96d56Sopenharmony_ci struct.calcsize(s) 7107db96d56Sopenharmony_ci 7117db96d56Sopenharmony_ci @support.cpython_only 7127db96d56Sopenharmony_ci def test_issue45034_unsigned(self): 7137db96d56Sopenharmony_ci _testcapi = import_helper.import_module('_testcapi') 7147db96d56Sopenharmony_ci error_msg = f'ushort format requires 0 <= number <= {_testcapi.USHRT_MAX}' 7157db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, error_msg): 7167db96d56Sopenharmony_ci struct.pack('H', 70000) # too large 7177db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, error_msg): 7187db96d56Sopenharmony_ci struct.pack('H', -1) # too small 7197db96d56Sopenharmony_ci 7207db96d56Sopenharmony_ci @support.cpython_only 7217db96d56Sopenharmony_ci def test_issue45034_signed(self): 7227db96d56Sopenharmony_ci _testcapi = import_helper.import_module('_testcapi') 7237db96d56Sopenharmony_ci error_msg = f'short format requires {_testcapi.SHRT_MIN} <= number <= {_testcapi.SHRT_MAX}' 7247db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, error_msg): 7257db96d56Sopenharmony_ci struct.pack('h', 70000) # too large 7267db96d56Sopenharmony_ci with self.assertRaisesRegex(struct.error, error_msg): 7277db96d56Sopenharmony_ci struct.pack('h', -70000) # too small 7287db96d56Sopenharmony_ci 7297db96d56Sopenharmony_ci 7307db96d56Sopenharmony_ciclass UnpackIteratorTest(unittest.TestCase): 7317db96d56Sopenharmony_ci """ 7327db96d56Sopenharmony_ci Tests for iterative unpacking (struct.Struct.iter_unpack). 7337db96d56Sopenharmony_ci """ 7347db96d56Sopenharmony_ci 7357db96d56Sopenharmony_ci def test_construct(self): 7367db96d56Sopenharmony_ci def _check_iterator(it): 7377db96d56Sopenharmony_ci self.assertIsInstance(it, abc.Iterator) 7387db96d56Sopenharmony_ci self.assertIsInstance(it, abc.Iterable) 7397db96d56Sopenharmony_ci s = struct.Struct('>ibcp') 7407db96d56Sopenharmony_ci it = s.iter_unpack(b"") 7417db96d56Sopenharmony_ci _check_iterator(it) 7427db96d56Sopenharmony_ci it = s.iter_unpack(b"1234567") 7437db96d56Sopenharmony_ci _check_iterator(it) 7447db96d56Sopenharmony_ci # Wrong bytes length 7457db96d56Sopenharmony_ci with self.assertRaises(struct.error): 7467db96d56Sopenharmony_ci s.iter_unpack(b"123456") 7477db96d56Sopenharmony_ci with self.assertRaises(struct.error): 7487db96d56Sopenharmony_ci s.iter_unpack(b"12345678") 7497db96d56Sopenharmony_ci # Zero-length struct 7507db96d56Sopenharmony_ci s = struct.Struct('>') 7517db96d56Sopenharmony_ci with self.assertRaises(struct.error): 7527db96d56Sopenharmony_ci s.iter_unpack(b"") 7537db96d56Sopenharmony_ci with self.assertRaises(struct.error): 7547db96d56Sopenharmony_ci s.iter_unpack(b"12") 7557db96d56Sopenharmony_ci 7567db96d56Sopenharmony_ci def test_uninstantiable(self): 7577db96d56Sopenharmony_ci iter_unpack_type = type(struct.Struct(">ibcp").iter_unpack(b"")) 7587db96d56Sopenharmony_ci self.assertRaises(TypeError, iter_unpack_type) 7597db96d56Sopenharmony_ci 7607db96d56Sopenharmony_ci def test_iterate(self): 7617db96d56Sopenharmony_ci s = struct.Struct('>IB') 7627db96d56Sopenharmony_ci b = bytes(range(1, 16)) 7637db96d56Sopenharmony_ci it = s.iter_unpack(b) 7647db96d56Sopenharmony_ci self.assertEqual(next(it), (0x01020304, 5)) 7657db96d56Sopenharmony_ci self.assertEqual(next(it), (0x06070809, 10)) 7667db96d56Sopenharmony_ci self.assertEqual(next(it), (0x0b0c0d0e, 15)) 7677db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 7687db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 7697db96d56Sopenharmony_ci 7707db96d56Sopenharmony_ci def test_arbitrary_buffer(self): 7717db96d56Sopenharmony_ci s = struct.Struct('>IB') 7727db96d56Sopenharmony_ci b = bytes(range(1, 11)) 7737db96d56Sopenharmony_ci it = s.iter_unpack(memoryview(b)) 7747db96d56Sopenharmony_ci self.assertEqual(next(it), (0x01020304, 5)) 7757db96d56Sopenharmony_ci self.assertEqual(next(it), (0x06070809, 10)) 7767db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 7777db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 7787db96d56Sopenharmony_ci 7797db96d56Sopenharmony_ci def test_length_hint(self): 7807db96d56Sopenharmony_ci lh = operator.length_hint 7817db96d56Sopenharmony_ci s = struct.Struct('>IB') 7827db96d56Sopenharmony_ci b = bytes(range(1, 16)) 7837db96d56Sopenharmony_ci it = s.iter_unpack(b) 7847db96d56Sopenharmony_ci self.assertEqual(lh(it), 3) 7857db96d56Sopenharmony_ci next(it) 7867db96d56Sopenharmony_ci self.assertEqual(lh(it), 2) 7877db96d56Sopenharmony_ci next(it) 7887db96d56Sopenharmony_ci self.assertEqual(lh(it), 1) 7897db96d56Sopenharmony_ci next(it) 7907db96d56Sopenharmony_ci self.assertEqual(lh(it), 0) 7917db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 7927db96d56Sopenharmony_ci self.assertEqual(lh(it), 0) 7937db96d56Sopenharmony_ci 7947db96d56Sopenharmony_ci def test_module_func(self): 7957db96d56Sopenharmony_ci # Sanity check for the global struct.iter_unpack() 7967db96d56Sopenharmony_ci it = struct.iter_unpack('>IB', bytes(range(1, 11))) 7977db96d56Sopenharmony_ci self.assertEqual(next(it), (0x01020304, 5)) 7987db96d56Sopenharmony_ci self.assertEqual(next(it), (0x06070809, 10)) 7997db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 8007db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, it) 8017db96d56Sopenharmony_ci 8027db96d56Sopenharmony_ci def test_half_float(self): 8037db96d56Sopenharmony_ci # Little-endian examples from: 8047db96d56Sopenharmony_ci # http://en.wikipedia.org/wiki/Half_precision_floating-point_format 8057db96d56Sopenharmony_ci format_bits_float__cleanRoundtrip_list = [ 8067db96d56Sopenharmony_ci (b'\x00\x3c', 1.0), 8077db96d56Sopenharmony_ci (b'\x00\xc0', -2.0), 8087db96d56Sopenharmony_ci (b'\xff\x7b', 65504.0), # (max half precision) 8097db96d56Sopenharmony_ci (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal) 8107db96d56Sopenharmony_ci (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal) 8117db96d56Sopenharmony_ci (b'\x00\x00', 0.0), 8127db96d56Sopenharmony_ci (b'\x00\x80', -0.0), 8137db96d56Sopenharmony_ci (b'\x00\x7c', float('+inf')), 8147db96d56Sopenharmony_ci (b'\x00\xfc', float('-inf')), 8157db96d56Sopenharmony_ci (b'\x55\x35', 0.333251953125), # ~= 1/3 8167db96d56Sopenharmony_ci ] 8177db96d56Sopenharmony_ci 8187db96d56Sopenharmony_ci for le_bits, f in format_bits_float__cleanRoundtrip_list: 8197db96d56Sopenharmony_ci be_bits = le_bits[::-1] 8207db96d56Sopenharmony_ci self.assertEqual(f, struct.unpack('<e', le_bits)[0]) 8217db96d56Sopenharmony_ci self.assertEqual(le_bits, struct.pack('<e', f)) 8227db96d56Sopenharmony_ci self.assertEqual(f, struct.unpack('>e', be_bits)[0]) 8237db96d56Sopenharmony_ci self.assertEqual(be_bits, struct.pack('>e', f)) 8247db96d56Sopenharmony_ci if sys.byteorder == 'little': 8257db96d56Sopenharmony_ci self.assertEqual(f, struct.unpack('e', le_bits)[0]) 8267db96d56Sopenharmony_ci self.assertEqual(le_bits, struct.pack('e', f)) 8277db96d56Sopenharmony_ci else: 8287db96d56Sopenharmony_ci self.assertEqual(f, struct.unpack('e', be_bits)[0]) 8297db96d56Sopenharmony_ci self.assertEqual(be_bits, struct.pack('e', f)) 8307db96d56Sopenharmony_ci 8317db96d56Sopenharmony_ci # Check for NaN handling: 8327db96d56Sopenharmony_ci format_bits__nan_list = [ 8337db96d56Sopenharmony_ci ('<e', b'\x01\xfc'), 8347db96d56Sopenharmony_ci ('<e', b'\x00\xfe'), 8357db96d56Sopenharmony_ci ('<e', b'\xff\xff'), 8367db96d56Sopenharmony_ci ('<e', b'\x01\x7c'), 8377db96d56Sopenharmony_ci ('<e', b'\x00\x7e'), 8387db96d56Sopenharmony_ci ('<e', b'\xff\x7f'), 8397db96d56Sopenharmony_ci ] 8407db96d56Sopenharmony_ci 8417db96d56Sopenharmony_ci for formatcode, bits in format_bits__nan_list: 8427db96d56Sopenharmony_ci self.assertTrue(math.isnan(struct.unpack('<e', bits)[0])) 8437db96d56Sopenharmony_ci self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0])) 8447db96d56Sopenharmony_ci 8457db96d56Sopenharmony_ci # Check that packing produces a bit pattern representing a quiet NaN: 8467db96d56Sopenharmony_ci # all exponent bits and the msb of the fraction should all be 1. 8477db96d56Sopenharmony_ci packed = struct.pack('<e', math.nan) 8487db96d56Sopenharmony_ci self.assertEqual(packed[1] & 0x7e, 0x7e) 8497db96d56Sopenharmony_ci packed = struct.pack('<e', -math.nan) 8507db96d56Sopenharmony_ci self.assertEqual(packed[1] & 0x7e, 0x7e) 8517db96d56Sopenharmony_ci 8527db96d56Sopenharmony_ci # Checks for round-to-even behavior 8537db96d56Sopenharmony_ci format_bits_float__rounding_list = [ 8547db96d56Sopenharmony_ci ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal 8557db96d56Sopenharmony_ci ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode) 8567db96d56Sopenharmony_ci ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero 8577db96d56Sopenharmony_ci ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal. 8587db96d56Sopenharmony_ci ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65), 8597db96d56Sopenharmony_ci ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25), 8607db96d56Sopenharmony_ci ('>e', b'\x04\x00', 2.0**-14), # Smallest normal. 8617db96d56Sopenharmony_ci ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10) 8627db96d56Sopenharmony_ci ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode) 8637db96d56Sopenharmony_ci ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0 8647db96d56Sopenharmony_ci ('>e', b'\x7b\xff', 65504), # largest normal 8657db96d56Sopenharmony_ci ('>e', b'\x7b\xff', 65519), # rounds to 65504 8667db96d56Sopenharmony_ci ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal 8677db96d56Sopenharmony_ci ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode) 8687db96d56Sopenharmony_ci ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero 8697db96d56Sopenharmony_ci ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10) 8707db96d56Sopenharmony_ci ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode) 8717db96d56Sopenharmony_ci ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0 8727db96d56Sopenharmony_ci ('>e', b'\xfb\xff', -65519), # rounds to 65504 8737db96d56Sopenharmony_ci ] 8747db96d56Sopenharmony_ci 8757db96d56Sopenharmony_ci for formatcode, bits, f in format_bits_float__rounding_list: 8767db96d56Sopenharmony_ci self.assertEqual(bits, struct.pack(formatcode, f)) 8777db96d56Sopenharmony_ci 8787db96d56Sopenharmony_ci # This overflows, and so raises an error 8797db96d56Sopenharmony_ci format_bits_float__roundingError_list = [ 8807db96d56Sopenharmony_ci # Values that round to infinity. 8817db96d56Sopenharmony_ci ('>e', 65520.0), 8827db96d56Sopenharmony_ci ('>e', 65536.0), 8837db96d56Sopenharmony_ci ('>e', 1e300), 8847db96d56Sopenharmony_ci ('>e', -65520.0), 8857db96d56Sopenharmony_ci ('>e', -65536.0), 8867db96d56Sopenharmony_ci ('>e', -1e300), 8877db96d56Sopenharmony_ci ('<e', 65520.0), 8887db96d56Sopenharmony_ci ('<e', 65536.0), 8897db96d56Sopenharmony_ci ('<e', 1e300), 8907db96d56Sopenharmony_ci ('<e', -65520.0), 8917db96d56Sopenharmony_ci ('<e', -65536.0), 8927db96d56Sopenharmony_ci ('<e', -1e300), 8937db96d56Sopenharmony_ci ] 8947db96d56Sopenharmony_ci 8957db96d56Sopenharmony_ci for formatcode, f in format_bits_float__roundingError_list: 8967db96d56Sopenharmony_ci self.assertRaises(OverflowError, struct.pack, formatcode, f) 8977db96d56Sopenharmony_ci 8987db96d56Sopenharmony_ci # Double rounding 8997db96d56Sopenharmony_ci format_bits_float__doubleRoundingError_list = [ 9007db96d56Sopenharmony_ci ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048 9017db96d56Sopenharmony_ci ] 9027db96d56Sopenharmony_ci 9037db96d56Sopenharmony_ci for formatcode, bits, f in format_bits_float__doubleRoundingError_list: 9047db96d56Sopenharmony_ci self.assertEqual(bits, struct.pack(formatcode, f)) 9057db96d56Sopenharmony_ci 9067db96d56Sopenharmony_ci 9077db96d56Sopenharmony_ciif __name__ == '__main__': 9087db96d56Sopenharmony_ci unittest.main() 909