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