Skip to content

Commit aeaead6

Browse files
committed
gh-155907: Move PyMarshal C API tests to test_capi
Add Modules/_testcapi/marshal.c and Lib/test/test_capi/test_marshal.py.
1 parent 658612a commit aeaead6

8 files changed

Lines changed: 305 additions & 273 deletions

File tree

Lib/test/test_capi/test_marshal.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import unittest
2+
3+
from test import support
4+
from test.support import import_helper
5+
from test.test_marshal import HelperMixin
6+
7+
8+
# Skip this test if _testcapi is are not available.
9+
_testcapi = import_helper.import_module('_testcapi')
10+
11+
12+
@support.cpython_only
13+
class CAPI_TestCase(unittest.TestCase, HelperMixin):
14+
15+
def test_read_from_file_error(self):
16+
# A read error is reported as OSError, not EOFError.
17+
# A directory cannot be read (on some platforms it cannot even
18+
# be opened, which is reported as OSError as well).
19+
os.mkdir(os_helper.TESTFN)
20+
self.addCleanup(os_helper.rmdir, os_helper.TESTFN)
21+
for func in (_testcapi.pymarshal_read_short_from_file,
22+
_testcapi.pymarshal_read_long_from_file,
23+
_testcapi.pymarshal_read_object_from_file,
24+
_testcapi.pymarshal_read_last_object_from_file):
25+
with self.subTest(func=func.__name__):
26+
self.assertRaises(OSError, func, os_helper.TESTFN)
27+
28+
@unittest.skipUnless(os.path.exists('/dev/full'), 'requires /dev/full')
29+
def test_write_to_file_error(self):
30+
# A write error is reported as OSError.
31+
# The data is large enough to not fit in the stdio buffer, so that
32+
# the error is detected before the file is closed.
33+
obj = b'x' * 100000
34+
with self.assertRaises(OSError):
35+
_testcapi.pymarshal_write_object_to_file(obj, '/dev/full',
36+
marshal.version)
37+
38+
def test_write_unmarshallable_to_file(self):
39+
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
40+
with self.assertRaisesRegex(ValueError, 'unmarshallable object'):
41+
_testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN,
42+
marshal.version)
43+
44+
def test_write_long_to_file(self):
45+
for v in range(marshal.version + 1):
46+
_testcapi.pymarshal_write_long_to_file(0x12345678, os_helper.TESTFN, v)
47+
with open(os_helper.TESTFN, 'rb') as f:
48+
data = f.read()
49+
os_helper.unlink(os_helper.TESTFN)
50+
self.assertEqual(data, b'\x78\x56\x34\x12')
51+
52+
def test_write_object_to_file(self):
53+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
54+
for v in range(marshal.version + 1):
55+
_testcapi.pymarshal_write_object_to_file(obj, os_helper.TESTFN, v)
56+
with open(os_helper.TESTFN, 'rb') as f:
57+
data = f.read()
58+
os_helper.unlink(os_helper.TESTFN)
59+
self.assertEqual(marshal.loads(data), obj)
60+
61+
def test_read_short_from_file(self):
62+
with open(os_helper.TESTFN, 'wb') as f:
63+
f.write(b'\x34\x12xxxx')
64+
r, p = _testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
65+
os_helper.unlink(os_helper.TESTFN)
66+
self.assertEqual(r, 0x1234)
67+
self.assertEqual(p, 2)
68+
69+
with open(os_helper.TESTFN, 'wb') as f:
70+
f.write(b'\x12')
71+
with self.assertRaises(EOFError):
72+
_testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
73+
os_helper.unlink(os_helper.TESTFN)
74+
75+
def test_read_long_from_file(self):
76+
with open(os_helper.TESTFN, 'wb') as f:
77+
f.write(b'\x78\x56\x34\x12xxxx')
78+
r, p = _testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
79+
os_helper.unlink(os_helper.TESTFN)
80+
self.assertEqual(r, 0x12345678)
81+
self.assertEqual(p, 4)
82+
83+
with open(os_helper.TESTFN, 'wb') as f:
84+
f.write(b'\x56\x34\x12')
85+
with self.assertRaises(EOFError):
86+
_testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
87+
os_helper.unlink(os_helper.TESTFN)
88+
89+
def test_read_last_object_from_file(self):
90+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
91+
for v in range(marshal.version + 1):
92+
data = marshal.dumps(obj, v)
93+
with open(os_helper.TESTFN, 'wb') as f:
94+
f.write(data + b'xxxx')
95+
r, p = _testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
96+
os_helper.unlink(os_helper.TESTFN)
97+
self.assertEqual(r, obj)
98+
99+
with open(os_helper.TESTFN, 'wb') as f:
100+
f.write(omit_last_byte(data))
101+
with self.assertRaises(EOFError):
102+
_testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
103+
os_helper.unlink(os_helper.TESTFN)
104+
105+
def test_read_object_from_file(self):
106+
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
107+
for v in range(marshal.version + 1):
108+
data = marshal.dumps(obj, v)
109+
with open(os_helper.TESTFN, 'wb') as f:
110+
f.write(data + b'xxxx')
111+
r, p = _testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
112+
os_helper.unlink(os_helper.TESTFN)
113+
self.assertEqual(r, obj)
114+
self.assertEqual(p, len(data))
115+
116+
with open(os_helper.TESTFN, 'wb') as f:
117+
f.write(omit_last_byte(data))
118+
with self.assertRaises(EOFError):
119+
_testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
120+
os_helper.unlink(os_helper.TESTFN)
121+
122+
123+
if __name__ == "__main__":
124+
unittest.main()

Lib/test/test_marshal.py

Lines changed: 0 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -797,117 +797,6 @@ def test_slice(self):
797797
with self.assertRaises(ValueError):
798798
marshal.dumps(obj, version)
799799

800-
@support.cpython_only
801-
@unittest.skipUnless(_testcapi, 'requires _testcapi')
802-
class CAPI_TestCase(unittest.TestCase, HelperMixin):
803-
804-
def test_read_from_file_error(self):
805-
# A read error is reported as OSError, not EOFError.
806-
# A directory cannot be read (on some platforms it cannot even
807-
# be opened, which is reported as OSError as well).
808-
os.mkdir(os_helper.TESTFN)
809-
self.addCleanup(os_helper.rmdir, os_helper.TESTFN)
810-
for func in (_testcapi.pymarshal_read_short_from_file,
811-
_testcapi.pymarshal_read_long_from_file,
812-
_testcapi.pymarshal_read_object_from_file,
813-
_testcapi.pymarshal_read_last_object_from_file):
814-
with self.subTest(func=func.__name__):
815-
self.assertRaises(OSError, func, os_helper.TESTFN)
816-
817-
@unittest.skipUnless(os.path.exists('/dev/full'), 'requires /dev/full')
818-
def test_write_to_file_error(self):
819-
# A write error is reported as OSError.
820-
# The data is large enough to not fit in the stdio buffer, so that
821-
# the error is detected before the file is closed.
822-
obj = b'x' * 100000
823-
with self.assertRaises(OSError):
824-
_testcapi.pymarshal_write_object_to_file(obj, '/dev/full',
825-
marshal.version)
826-
827-
def test_write_unmarshallable_to_file(self):
828-
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
829-
with self.assertRaisesRegex(ValueError, 'unmarshallable object'):
830-
_testcapi.pymarshal_write_object_to_file(object(), os_helper.TESTFN,
831-
marshal.version)
832-
833-
def test_write_long_to_file(self):
834-
for v in range(marshal.version + 1):
835-
_testcapi.pymarshal_write_long_to_file(0x12345678, os_helper.TESTFN, v)
836-
with open(os_helper.TESTFN, 'rb') as f:
837-
data = f.read()
838-
os_helper.unlink(os_helper.TESTFN)
839-
self.assertEqual(data, b'\x78\x56\x34\x12')
840-
841-
def test_write_object_to_file(self):
842-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j, 'long line '*1000)
843-
for v in range(marshal.version + 1):
844-
_testcapi.pymarshal_write_object_to_file(obj, os_helper.TESTFN, v)
845-
with open(os_helper.TESTFN, 'rb') as f:
846-
data = f.read()
847-
os_helper.unlink(os_helper.TESTFN)
848-
self.assertEqual(marshal.loads(data), obj)
849-
850-
def test_read_short_from_file(self):
851-
with open(os_helper.TESTFN, 'wb') as f:
852-
f.write(b'\x34\x12xxxx')
853-
r, p = _testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
854-
os_helper.unlink(os_helper.TESTFN)
855-
self.assertEqual(r, 0x1234)
856-
self.assertEqual(p, 2)
857-
858-
with open(os_helper.TESTFN, 'wb') as f:
859-
f.write(b'\x12')
860-
with self.assertRaises(EOFError):
861-
_testcapi.pymarshal_read_short_from_file(os_helper.TESTFN)
862-
os_helper.unlink(os_helper.TESTFN)
863-
864-
def test_read_long_from_file(self):
865-
with open(os_helper.TESTFN, 'wb') as f:
866-
f.write(b'\x78\x56\x34\x12xxxx')
867-
r, p = _testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
868-
os_helper.unlink(os_helper.TESTFN)
869-
self.assertEqual(r, 0x12345678)
870-
self.assertEqual(p, 4)
871-
872-
with open(os_helper.TESTFN, 'wb') as f:
873-
f.write(b'\x56\x34\x12')
874-
with self.assertRaises(EOFError):
875-
_testcapi.pymarshal_read_long_from_file(os_helper.TESTFN)
876-
os_helper.unlink(os_helper.TESTFN)
877-
878-
def test_read_last_object_from_file(self):
879-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
880-
for v in range(marshal.version + 1):
881-
data = marshal.dumps(obj, v)
882-
with open(os_helper.TESTFN, 'wb') as f:
883-
f.write(data + b'xxxx')
884-
r, p = _testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
885-
os_helper.unlink(os_helper.TESTFN)
886-
self.assertEqual(r, obj)
887-
888-
with open(os_helper.TESTFN, 'wb') as f:
889-
f.write(omit_last_byte(data))
890-
with self.assertRaises(EOFError):
891-
_testcapi.pymarshal_read_last_object_from_file(os_helper.TESTFN)
892-
os_helper.unlink(os_helper.TESTFN)
893-
894-
def test_read_object_from_file(self):
895-
obj = ('\u20ac', b'abc', 123, 45.6, 7+8j)
896-
for v in range(marshal.version + 1):
897-
data = marshal.dumps(obj, v)
898-
with open(os_helper.TESTFN, 'wb') as f:
899-
f.write(data + b'xxxx')
900-
r, p = _testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
901-
os_helper.unlink(os_helper.TESTFN)
902-
self.assertEqual(r, obj)
903-
self.assertEqual(p, len(data))
904-
905-
with open(os_helper.TESTFN, 'wb') as f:
906-
f.write(omit_last_byte(data))
907-
with self.assertRaises(EOFError):
908-
_testcapi.pymarshal_read_object_from_file(os_helper.TESTFN)
909-
os_helper.unlink(os_helper.TESTFN)
910-
911800

912801
if __name__ == "__main__":
913802
unittest.main()

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
174174
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
175175
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tokenizer.c _testinternalcapi/tuple.c _testinternalcapi/typecache.c
176-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
176+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c _testcapi/marshal.c
177177
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/capsule.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c _testlimitedcapi/type.c
178178
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
179179
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

0 commit comments

Comments
 (0)