python (3.12.0)

(root)/
lib/
python3.12/
test/
test_struct.py
       1  from collections import abc
       2  import array
       3  import gc
       4  import math
       5  import operator
       6  import unittest
       7  import struct
       8  import sys
       9  import weakref
      10  
      11  from test import support
      12  from test.support import import_helper
      13  from test.support.script_helper import assert_python_ok
      14  
      15  ISBIGENDIAN = sys.byteorder == "big"
      16  
      17  integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
      18  byteorders = '', '@', '=', '<', '>', '!'
      19  
      20  def 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  
      27  def string_reverse(s):
      28      return s[::-1]
      29  
      30  def bigendian_to_native(value):
      31      if ISBIGENDIAN:
      32          return value
      33      else:
      34          return string_reverse(value)
      35  
      36  class ESC[4;38;5;81mStructTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      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 ESC[4;38;5;81mIntTester(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     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 ESC[4;38;5;81mNotAnInt:
     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 ESC[4;38;5;81mIndexable(ESC[4;38;5;149mobject):
     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 ESC[4;38;5;81mBadIndex(ESC[4;38;5;149mobject):
     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 ESC[4;38;5;81mExplodingBool(ESC[4;38;5;149mobject):
     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      @support.cpython_only
     704      def test__struct_Struct__new__initialized(self):
     705          # See https://github.com/python/cpython/issues/78724
     706  
     707          s = struct.Struct.__new__(struct.Struct, "b")
     708          s.unpack_from(b"abcd")
     709  
     710      @support.cpython_only
     711      def test__struct_Struct_subclassing(self):
     712          class ESC[4;38;5;81mBob(ESC[4;38;5;149mstructESC[4;38;5;149m.ESC[4;38;5;149mStruct):
     713              pass
     714  
     715          s = Bob("b")
     716          s.unpack_from(b"abcd")
     717  
     718      def test_issue35714(self):
     719          # Embedded null characters should not be allowed in format strings.
     720          for s in '\0', '2\0i', b'\0':
     721              with self.assertRaisesRegex(struct.error,
     722                                          'embedded null character'):
     723                  struct.calcsize(s)
     724  
     725      @support.cpython_only
     726      def test_issue98248(self):
     727          def test_error_msg(prefix, int_type, is_unsigned):
     728              fmt_str = prefix + int_type
     729              size = struct.calcsize(fmt_str)
     730              if is_unsigned:
     731                  max_ = 2 ** (size * 8) - 1
     732                  min_ = 0
     733              else:
     734                  max_ = 2 ** (size * 8 - 1) - 1
     735                  min_ = -2 ** (size * 8 - 1)
     736              error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}"
     737              for number in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]:
     738                  with self.subTest(format_str=fmt_str, number=number):
     739                      with self.assertRaisesRegex(struct.error, error_msg):
     740                          struct.pack(fmt_str, number)
     741              error_msg = "required argument is not an integer"
     742              not_number = ""
     743              with self.subTest(format_str=fmt_str, number=not_number):
     744                  with self.assertRaisesRegex(struct.error, error_msg):
     745                      struct.pack(fmt_str, not_number)
     746  
     747          for prefix in '@=<>':
     748              for int_type in 'BHILQ':
     749                  test_error_msg(prefix, int_type, True)
     750              for int_type in 'bhilq':
     751                  test_error_msg(prefix, int_type, False)
     752  
     753          int_type = 'N'
     754          test_error_msg('@', int_type, True)
     755  
     756          int_type = 'n'
     757          test_error_msg('@', int_type, False)
     758  
     759      @support.cpython_only
     760      def test_issue98248_error_propagation(self):
     761          class ESC[4;38;5;81mDiv0:
     762              def __index__(self):
     763                  1 / 0
     764  
     765          def test_error_propagation(fmt_str):
     766              with self.subTest(format_str=fmt_str, exception="ZeroDivisionError"):
     767                  with self.assertRaises(ZeroDivisionError):
     768                      struct.pack(fmt_str, Div0())
     769  
     770          for prefix in '@=<>':
     771              for int_type in 'BHILQbhilq':
     772                  test_error_propagation(prefix + int_type)
     773  
     774          test_error_propagation('N')
     775          test_error_propagation('n')
     776  
     777  class ESC[4;38;5;81mUnpackIteratorTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     778      """
     779      Tests for iterative unpacking (struct.Struct.iter_unpack).
     780      """
     781  
     782      def test_construct(self):
     783          def _check_iterator(it):
     784              self.assertIsInstance(it, abc.Iterator)
     785              self.assertIsInstance(it, abc.Iterable)
     786          s = struct.Struct('>ibcp')
     787          it = s.iter_unpack(b"")
     788          _check_iterator(it)
     789          it = s.iter_unpack(b"1234567")
     790          _check_iterator(it)
     791          # Wrong bytes length
     792          with self.assertRaises(struct.error):
     793              s.iter_unpack(b"123456")
     794          with self.assertRaises(struct.error):
     795              s.iter_unpack(b"12345678")
     796          # Zero-length struct
     797          s = struct.Struct('>')
     798          with self.assertRaises(struct.error):
     799              s.iter_unpack(b"")
     800          with self.assertRaises(struct.error):
     801              s.iter_unpack(b"12")
     802  
     803      def test_uninstantiable(self):
     804          iter_unpack_type = type(struct.Struct(">ibcp").iter_unpack(b""))
     805          self.assertRaises(TypeError, iter_unpack_type)
     806  
     807      def test_iterate(self):
     808          s = struct.Struct('>IB')
     809          b = bytes(range(1, 16))
     810          it = s.iter_unpack(b)
     811          self.assertEqual(next(it), (0x01020304, 5))
     812          self.assertEqual(next(it), (0x06070809, 10))
     813          self.assertEqual(next(it), (0x0b0c0d0e, 15))
     814          self.assertRaises(StopIteration, next, it)
     815          self.assertRaises(StopIteration, next, it)
     816  
     817      def test_arbitrary_buffer(self):
     818          s = struct.Struct('>IB')
     819          b = bytes(range(1, 11))
     820          it = s.iter_unpack(memoryview(b))
     821          self.assertEqual(next(it), (0x01020304, 5))
     822          self.assertEqual(next(it), (0x06070809, 10))
     823          self.assertRaises(StopIteration, next, it)
     824          self.assertRaises(StopIteration, next, it)
     825  
     826      def test_length_hint(self):
     827          lh = operator.length_hint
     828          s = struct.Struct('>IB')
     829          b = bytes(range(1, 16))
     830          it = s.iter_unpack(b)
     831          self.assertEqual(lh(it), 3)
     832          next(it)
     833          self.assertEqual(lh(it), 2)
     834          next(it)
     835          self.assertEqual(lh(it), 1)
     836          next(it)
     837          self.assertEqual(lh(it), 0)
     838          self.assertRaises(StopIteration, next, it)
     839          self.assertEqual(lh(it), 0)
     840  
     841      def test_module_func(self):
     842          # Sanity check for the global struct.iter_unpack()
     843          it = struct.iter_unpack('>IB', bytes(range(1, 11)))
     844          self.assertEqual(next(it), (0x01020304, 5))
     845          self.assertEqual(next(it), (0x06070809, 10))
     846          self.assertRaises(StopIteration, next, it)
     847          self.assertRaises(StopIteration, next, it)
     848  
     849      def test_half_float(self):
     850          # Little-endian examples from:
     851          # http://en.wikipedia.org/wiki/Half_precision_floating-point_format
     852          format_bits_float__cleanRoundtrip_list = [
     853              (b'\x00\x3c', 1.0),
     854              (b'\x00\xc0', -2.0),
     855              (b'\xff\x7b', 65504.0), #  (max half precision)
     856              (b'\x00\x04', 2**-14), # ~= 6.10352 * 10**-5 (min pos normal)
     857              (b'\x01\x00', 2**-24), # ~= 5.96046 * 10**-8 (min pos subnormal)
     858              (b'\x00\x00', 0.0),
     859              (b'\x00\x80', -0.0),
     860              (b'\x00\x7c', float('+inf')),
     861              (b'\x00\xfc', float('-inf')),
     862              (b'\x55\x35', 0.333251953125), # ~= 1/3
     863          ]
     864  
     865          for le_bits, f in format_bits_float__cleanRoundtrip_list:
     866              be_bits = le_bits[::-1]
     867              self.assertEqual(f, struct.unpack('<e', le_bits)[0])
     868              self.assertEqual(le_bits, struct.pack('<e', f))
     869              self.assertEqual(f, struct.unpack('>e', be_bits)[0])
     870              self.assertEqual(be_bits, struct.pack('>e', f))
     871              if sys.byteorder == 'little':
     872                  self.assertEqual(f, struct.unpack('e', le_bits)[0])
     873                  self.assertEqual(le_bits, struct.pack('e', f))
     874              else:
     875                  self.assertEqual(f, struct.unpack('e', be_bits)[0])
     876                  self.assertEqual(be_bits, struct.pack('e', f))
     877  
     878          # Check for NaN handling:
     879          format_bits__nan_list = [
     880              ('<e', b'\x01\xfc'),
     881              ('<e', b'\x00\xfe'),
     882              ('<e', b'\xff\xff'),
     883              ('<e', b'\x01\x7c'),
     884              ('<e', b'\x00\x7e'),
     885              ('<e', b'\xff\x7f'),
     886          ]
     887  
     888          for formatcode, bits in format_bits__nan_list:
     889              self.assertTrue(math.isnan(struct.unpack('<e', bits)[0]))
     890              self.assertTrue(math.isnan(struct.unpack('>e', bits[::-1])[0]))
     891  
     892          # Check that packing produces a bit pattern representing a quiet NaN:
     893          # all exponent bits and the msb of the fraction should all be 1.
     894          packed = struct.pack('<e', math.nan)
     895          self.assertEqual(packed[1] & 0x7e, 0x7e)
     896          packed = struct.pack('<e', -math.nan)
     897          self.assertEqual(packed[1] & 0x7e, 0x7e)
     898  
     899          # Checks for round-to-even behavior
     900          format_bits_float__rounding_list = [
     901              ('>e', b'\x00\x01', 2.0**-25 + 2.0**-35), # Rounds to minimum subnormal
     902              ('>e', b'\x00\x00', 2.0**-25), # Underflows to zero (nearest even mode)
     903              ('>e', b'\x00\x00', 2.0**-26), # Underflows to zero
     904              ('>e', b'\x03\xff', 2.0**-14 - 2.0**-24), # Largest subnormal.
     905              ('>e', b'\x03\xff', 2.0**-14 - 2.0**-25 - 2.0**-65),
     906              ('>e', b'\x04\x00', 2.0**-14 - 2.0**-25),
     907              ('>e', b'\x04\x00', 2.0**-14), # Smallest normal.
     908              ('>e', b'\x3c\x01', 1.0+2.0**-11 + 2.0**-16), # rounds to 1.0+2**(-10)
     909              ('>e', b'\x3c\x00', 1.0+2.0**-11), # rounds to 1.0 (nearest even mode)
     910              ('>e', b'\x3c\x00', 1.0+2.0**-12), # rounds to 1.0
     911              ('>e', b'\x7b\xff', 65504), # largest normal
     912              ('>e', b'\x7b\xff', 65519), # rounds to 65504
     913              ('>e', b'\x80\x01', -2.0**-25 - 2.0**-35), # Rounds to minimum subnormal
     914              ('>e', b'\x80\x00', -2.0**-25), # Underflows to zero (nearest even mode)
     915              ('>e', b'\x80\x00', -2.0**-26), # Underflows to zero
     916              ('>e', b'\xbc\x01', -1.0-2.0**-11 - 2.0**-16), # rounds to 1.0+2**(-10)
     917              ('>e', b'\xbc\x00', -1.0-2.0**-11), # rounds to 1.0 (nearest even mode)
     918              ('>e', b'\xbc\x00', -1.0-2.0**-12), # rounds to 1.0
     919              ('>e', b'\xfb\xff', -65519), # rounds to 65504
     920          ]
     921  
     922          for formatcode, bits, f in format_bits_float__rounding_list:
     923              self.assertEqual(bits, struct.pack(formatcode, f))
     924  
     925          # This overflows, and so raises an error
     926          format_bits_float__roundingError_list = [
     927              # Values that round to infinity.
     928              ('>e', 65520.0),
     929              ('>e', 65536.0),
     930              ('>e', 1e300),
     931              ('>e', -65520.0),
     932              ('>e', -65536.0),
     933              ('>e', -1e300),
     934              ('<e', 65520.0),
     935              ('<e', 65536.0),
     936              ('<e', 1e300),
     937              ('<e', -65520.0),
     938              ('<e', -65536.0),
     939              ('<e', -1e300),
     940          ]
     941  
     942          for formatcode, f in format_bits_float__roundingError_list:
     943              self.assertRaises(OverflowError, struct.pack, formatcode, f)
     944  
     945          # Double rounding
     946          format_bits_float__doubleRoundingError_list = [
     947              ('>e', b'\x67\xff', 0x1ffdffffff * 2**-26), # should be 2047, if double-rounded 64>32>16, becomes 2048
     948          ]
     949  
     950          for formatcode, bits, f in format_bits_float__doubleRoundingError_list:
     951              self.assertEqual(bits, struct.pack(formatcode, f))
     952  
     953  
     954  if __name__ == '__main__':
     955      unittest.main()