Skip to content

Commit bbdf31d

Browse files
authored
gh-155907: Move PyMarshal C API tests to test_capi (#157417)
Add Modules/_testcapi/marshal.c and Lib/test/test_capi/test_marshal.py.
1 parent 0ba7be9 commit bbdf31d

8 files changed

Lines changed: 308 additions & 273 deletions

File tree

Lib/test/test_capi/test_marshal.py

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