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