Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
]

from _struct import *
from _struct import _clearcache
from _struct import __doc__
from _struct import _clearcache # noqa: F401
from _struct import __doc__ # noqa: F401
63 changes: 50 additions & 13 deletions Lib/test/test_struct.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
from collections import abc
from itertools import combinations
import array
import gc
import math
import operator
import unittest
import platform
import struct
import sys
import weakref

from test import support
from test.support import import_helper, suppress_immortalization
from test.support import import_helper
from test.support.script_helper import assert_python_ok
from test.support.testcase import ComplexesAreIdenticalMixin

ISBIGENDIAN = sys.byteorder == "big"

integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
byteorders = '', '@', '=', '<', '>', '!'

INF = float('inf')
NAN = float('nan')

def iter_integer_formats(byteorders=byteorders):
for code in integer_codes:
for byteorder in byteorders:
Expand All @@ -33,7 +39,7 @@ def bigendian_to_native(value):
else:
return string_reverse(value)

class StructTest(unittest.TestCase):
class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
def test_isbigendian(self):
self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)

Expand Down Expand Up @@ -360,8 +366,7 @@ def test_p_code(self):
(got,) = struct.unpack(code, got)
self.assertEqual(got, expectedback)

# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_705836(self):
# SF bug 705836. "<f" and ">f" had a severe rounding bug, where a carry
# from the low-order discarded bits could propagate into the exponent
Expand Down Expand Up @@ -670,8 +675,7 @@ def test_format_attr(self):
s2 = struct.Struct(s.format.encode())
self.assertEqual(s2.format, s.format)

# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_struct_cleans_up_at_runtime_shutdown(self):
code = """if 1:
import struct
Expand All @@ -687,10 +691,9 @@ def __del__(self):
rc, stdout, stderr = assert_python_ok("-c", code)
self.assertEqual(rc, 0)
self.assertEqual(stdout.rstrip(), b"")
self.assertIn(b"Exception ignored in:", stderr)
self.assertIn(b"Exception ignored while calling deallocator", stderr)
self.assertIn(b"C.__del__", stderr)

@suppress_immortalization()
def test__struct_reference_cycle_cleaned_up(self):
# Regression test for python/cpython#94207.

Expand Down Expand Up @@ -777,8 +780,7 @@ def test_error_propagation(fmt_str):
test_error_propagation('N')
test_error_propagation('n')

# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_struct_subclass_instantiation(self):
# Regression test for https://github.com/python/cpython/issues/112358
class MyStruct(struct.Struct):
Expand All @@ -792,6 +794,34 @@ def test_repr(self):
s = struct.Struct('=i2H')
self.assertEqual(repr(s), f'Struct({s.format!r})')

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_c_complex_round_trip(self):
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
-3, INF, -INF, NAN], 2)]
for z in values:
for f in ['F', 'D', '>F', '>D', '<F', '<D']:
with self.subTest(z=z, format=f):
round_trip = struct.unpack(f, struct.pack(f, z))[0]
self.assertComplexesAreIdentical(z, round_trip)

@unittest.skipIf(
support.is_android or support.is_apple_mobile,
"Subinterpreters are not supported on Android and iOS"
)
def test_endian_table_init_subinterpreters(self):
# Verify that the _struct extension module can be initialized
# concurrently in subinterpreters (gh-140260).
try:
from concurrent.futures import InterpreterPoolExecutor
except ImportError:
raise unittest.SkipTest("InterpreterPoolExecutor not available")

code = "import struct"
with InterpreterPoolExecutor(max_workers=5) as executor:
results = executor.map(exec, [code] * 5)
self.assertListEqual(list(results), [None] * 5)


class UnpackIteratorTest(unittest.TestCase):
"""
Tests for iterative unpacking (struct.Struct.iter_unpack).
Expand Down Expand Up @@ -909,10 +939,17 @@ def test_half_float(self):

# Check that packing produces a bit pattern representing a quiet NaN:
# all exponent bits and the msb of the fraction should all be 1.
if platform.machine().startswith('parisc'):
# HP PA RISC uses 0 for quiet, see:
# https://en.wikipedia.org/wiki/NaN#Encoding
expected = 0x7c
else:
expected = 0x7e

packed = struct.pack('<e', math.nan)
self.assertEqual(packed[1] & 0x7e, 0x7e)
self.assertEqual(packed[1] & 0x7e, expected)
packed = struct.pack('<e', -math.nan)
self.assertEqual(packed[1] & 0x7e, 0x7e)
self.assertEqual(packed[1] & 0x7e, expected)

# Checks for round-to-even behavior
format_bits_float__rounding_list = [
Expand Down Expand Up @@ -970,4 +1007,4 @@ def test_half_float(self):


if __name__ == '__main__':
unittest.main()
unittest.main()
Loading