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