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