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