diff --git a/Lib/test/test_capi/test_marshal.py b/Lib/test/test_capi/test_marshal.py index 82a20c44fac424..972ff4ed53d687 100644 --- a/Lib/test/test_capi/test_marshal.py +++ b/Lib/test/test_capi/test_marshal.py @@ -1,19 +1,54 @@ +# Test PyMarshal C API + import marshal import os.path +import struct import unittest from test import support from test.support import import_helper from test.support import os_helper -from test.test_marshal import HelperMixin, omit_last_byte # Skip this test if _testcapi is are not available. _testcapi = import_helper.import_module('_testcapi') +def noop_func(): + pass + +NULL = None +SIMPLE_OBJECT = 123 +# Only test a few objects: see test_marshal for more exhaustive tests +TEST_OBJECTS = ( + '\u20ac', + b'abc', + True, + 123, + 45.6, + 7+8j, + 'long line '*1000, + # Check that serializing code object is allowed (allow_code = 1) + noop_func.__code__, +) +UNMARSHALLABLE = object() + +# Invalid marshal data +JUNK_BYTES = b'\xff' * 32 + + +def read_file(filename): + with open(filename, 'rb') as fp: + return fp.read() + + +def write_file(filename, data): + with open(filename, 'wb') as fp: + fp.write(data) + + @support.cpython_only -class CAPI_TestCase(unittest.TestCase, HelperMixin): +class CAPI_TestCase(unittest.TestCase): def test_read_from_file_error(self): # A read error is reported as OSError, not EOFError. @@ -38,89 +73,163 @@ def test_write_to_file_error(self): _testcapi.pymarshal_write_object_to_file(obj, '/dev/full', marshal.version) - def test_write_unmarshallable_to_file(self): - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - with self.assertRaisesRegex(ValueError, 'unmarshallable object'): - _testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN, - marshal.version) + def check_object(self, obj2, obj): + self.assertEqual(obj2, obj) + self.assertEqual(type(obj2), type(obj)) def test_write_long_to_file(self): - for v in range(marshal.version + 1): - _testcapi.pymarshal_write_long_to_file(0x12345678, os_helper.TESTFN, v) - with open(os_helper.TESTFN, 'rb') as f: - data = f.read() - os_helper.unlink(os_helper.TESTFN) - self.assertEqual(data, b'\x78\x56\x34\x12') + # Test PyMarshal_WriteLongToFile() + write_long_to_file = _testcapi.pymarshal_write_long_to_file + filename = os_helper.TESTFN + self.addCleanup(os_helper.unlink, filename) + + def mask32(value): + res = value & (2 ** 32 - 1) + if res >= 2147483648: + return res - 4294967296 + else: + return res + + limit = 2 ** 31 + values = [ + _testcapi.LONG_MIN, _testcapi.LONG_MAX, + -limit, -limit + 2, limit - 2, limit - 1, + 0, 123, -123, + ] + # Test values larger than 32-bit on platforms with 64-bit C long + if _testcapi.LONG_MAX > (2**31-1): + values.extend((-limit - 2, limit, limit + 2)) + + for version in range(marshal.version + 1): + for value in values: + with self.subTest(value=value, version=version): + write_long_to_file(value, filename, version) + data = read_file(filename) + self.assertEqual(len(data), 4) + value2 = struct.unpack('