Skip to content

Commit c28ff5f

Browse files
committed
gh-138013: Move buffered tests to test_bufferedio
This moves test support code to `test_io._support` and buffered test cases to `test_io.test_bufferedio` via copy/paste code movement then adjusts imports as needed (remove unneded + add all required).
1 parent 007bc5f commit c28ff5f

3 files changed

Lines changed: 1768 additions & 1751 deletions

File tree

Lib/test/test_io/_support.py

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
import array
2+
import threading
3+
import time
4+
import unittest
5+
6+
import io # C implementation of io
7+
import _pyio as pyio # Python implementation of io
8+
9+
10+
try:
11+
import ctypes
12+
except ImportError:
13+
def byteslike(*pos, **kw):
14+
return array.array("b", bytes(*pos, **kw))
15+
else:
16+
def byteslike(*pos, **kw):
17+
"""Create a bytes-like object having no string or sequence methods"""
18+
data = bytes(*pos, **kw)
19+
obj = EmptyStruct()
20+
ctypes.resize(obj, len(data))
21+
memoryview(obj).cast("B")[:] = data
22+
return obj
23+
class EmptyStruct(ctypes.Structure):
24+
pass
25+
26+
27+
class MockRawIOWithoutRead:
28+
"""A RawIO implementation without read(), so as to exercise the default
29+
RawIO.read() which calls readinto()."""
30+
31+
def __init__(self, read_stack=()):
32+
self._read_stack = list(read_stack)
33+
self._write_stack = []
34+
self._reads = 0
35+
self._extraneous_reads = 0
36+
37+
def write(self, b):
38+
self._write_stack.append(bytes(b))
39+
return len(b)
40+
41+
def writable(self):
42+
return True
43+
44+
def fileno(self):
45+
return 42
46+
47+
def readable(self):
48+
return True
49+
50+
def seekable(self):
51+
return True
52+
53+
def seek(self, pos, whence):
54+
return 0 # wrong but we gotta return something
55+
56+
def tell(self):
57+
return 0 # same comment as above
58+
59+
def readinto(self, buf):
60+
self._reads += 1
61+
max_len = len(buf)
62+
try:
63+
data = self._read_stack[0]
64+
except IndexError:
65+
self._extraneous_reads += 1
66+
return 0
67+
if data is None:
68+
del self._read_stack[0]
69+
return None
70+
n = len(data)
71+
if len(data) <= max_len:
72+
del self._read_stack[0]
73+
buf[:n] = data
74+
return n
75+
else:
76+
buf[:] = data[:max_len]
77+
self._read_stack[0] = data[max_len:]
78+
return max_len
79+
80+
def truncate(self, pos=None):
81+
return pos
82+
83+
class CMockRawIOWithoutRead(MockRawIOWithoutRead, io.RawIOBase):
84+
pass
85+
86+
class PyMockRawIOWithoutRead(MockRawIOWithoutRead, pyio.RawIOBase):
87+
pass
88+
89+
90+
class MockRawIO(MockRawIOWithoutRead):
91+
92+
def read(self, n=None):
93+
self._reads += 1
94+
try:
95+
return self._read_stack.pop(0)
96+
except:
97+
self._extraneous_reads += 1
98+
return b""
99+
100+
class CMockRawIO(MockRawIO, io.RawIOBase):
101+
pass
102+
103+
class PyMockRawIO(MockRawIO, pyio.RawIOBase):
104+
pass
105+
106+
107+
class MisbehavedRawIO(MockRawIO):
108+
def write(self, b):
109+
return super().write(b) * 2
110+
111+
def read(self, n=None):
112+
return super().read(n) * 2
113+
114+
def seek(self, pos, whence):
115+
return -123
116+
117+
def tell(self):
118+
return -456
119+
120+
def readinto(self, buf):
121+
super().readinto(buf)
122+
return len(buf) * 5
123+
124+
class CMisbehavedRawIO(MisbehavedRawIO, io.RawIOBase):
125+
pass
126+
127+
class PyMisbehavedRawIO(MisbehavedRawIO, pyio.RawIOBase):
128+
pass
129+
130+
131+
class SlowFlushRawIO(MockRawIO):
132+
def __init__(self):
133+
super().__init__()
134+
self.in_flush = threading.Event()
135+
136+
def flush(self):
137+
self.in_flush.set()
138+
time.sleep(0.25)
139+
140+
class CSlowFlushRawIO(SlowFlushRawIO, io.RawIOBase):
141+
pass
142+
143+
class PySlowFlushRawIO(SlowFlushRawIO, pyio.RawIOBase):
144+
pass
145+
146+
147+
class CloseFailureIO(MockRawIO):
148+
closed = 0
149+
150+
def close(self):
151+
if not self.closed:
152+
self.closed = 1
153+
raise OSError
154+
155+
class CCloseFailureIO(CloseFailureIO, io.RawIOBase):
156+
pass
157+
158+
class PyCloseFailureIO(CloseFailureIO, pyio.RawIOBase):
159+
pass
160+
161+
162+
class MockFileIO:
163+
164+
def __init__(self, data):
165+
self.read_history = []
166+
super().__init__(data)
167+
168+
def read(self, n=None):
169+
res = super().read(n)
170+
self.read_history.append(None if res is None else len(res))
171+
return res
172+
173+
def readinto(self, b):
174+
res = super().readinto(b)
175+
self.read_history.append(res)
176+
return res
177+
178+
class CMockFileIO(MockFileIO, io.BytesIO):
179+
pass
180+
181+
class PyMockFileIO(MockFileIO, pyio.BytesIO):
182+
pass
183+
184+
185+
class MockUnseekableIO:
186+
def seekable(self):
187+
return False
188+
189+
def seek(self, *args):
190+
raise self.UnsupportedOperation("not seekable")
191+
192+
def tell(self, *args):
193+
raise self.UnsupportedOperation("not seekable")
194+
195+
def truncate(self, *args):
196+
raise self.UnsupportedOperation("not seekable")
197+
198+
class CMockUnseekableIO(MockUnseekableIO, io.BytesIO):
199+
UnsupportedOperation = io.UnsupportedOperation
200+
201+
class PyMockUnseekableIO(MockUnseekableIO, pyio.BytesIO):
202+
UnsupportedOperation = pyio.UnsupportedOperation
203+
204+
205+
class MockCharPseudoDevFileIO(MockFileIO):
206+
# GH-95782
207+
# ftruncate() does not work on these special files (and CPython then raises
208+
# appropriate exceptions), so truncate() does not have to be accounted for
209+
# here.
210+
def __init__(self, data):
211+
super().__init__(data)
212+
213+
def seek(self, *args):
214+
return 0
215+
216+
def tell(self, *args):
217+
return 0
218+
219+
class CMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, io.BytesIO):
220+
pass
221+
222+
class PyMockCharPseudoDevFileIO(MockCharPseudoDevFileIO, pyio.BytesIO):
223+
pass
224+
225+
226+
class MockNonBlockWriterIO:
227+
228+
def __init__(self):
229+
self._write_stack = []
230+
self._blocker_char = None
231+
232+
def pop_written(self):
233+
s = b"".join(self._write_stack)
234+
self._write_stack[:] = []
235+
return s
236+
237+
def block_on(self, char):
238+
"""Block when a given char is encountered."""
239+
self._blocker_char = char
240+
241+
def readable(self):
242+
return True
243+
244+
def seekable(self):
245+
return True
246+
247+
def seek(self, pos, whence=0):
248+
# naive implementation, enough for tests
249+
return 0
250+
251+
def writable(self):
252+
return True
253+
254+
def write(self, b):
255+
b = bytes(b)
256+
n = -1
257+
if self._blocker_char:
258+
try:
259+
n = b.index(self._blocker_char)
260+
except ValueError:
261+
pass
262+
else:
263+
if n > 0:
264+
# write data up to the first blocker
265+
self._write_stack.append(b[:n])
266+
return n
267+
else:
268+
# cancel blocker and indicate would block
269+
self._blocker_char = None
270+
return None
271+
self._write_stack.append(b)
272+
return len(b)
273+
274+
class CMockNonBlockWriterIO(MockNonBlockWriterIO, io.RawIOBase):
275+
BlockingIOError = io.BlockingIOError
276+
277+
class PyMockNonBlockWriterIO(MockNonBlockWriterIO, pyio.RawIOBase):
278+
BlockingIOError = pyio.BlockingIOError
279+
280+
281+
# Build classes which point to all the right mocks per io implementation
282+
class CTestCase(unittest.TestCase):
283+
io = io
284+
is_C = True
285+
286+
MockRawIO = CMockRawIO
287+
MisbehavedRawIO = CMisbehavedRawIO
288+
MockFileIO = CMockFileIO
289+
CloseFailureIO = CCloseFailureIO
290+
MockNonBlockWriterIO = CMockNonBlockWriterIO
291+
MockUnseekableIO = CMockUnseekableIO
292+
MockRawIOWithoutRead = CMockRawIOWithoutRead
293+
SlowFlushRawIO = CSlowFlushRawIO
294+
MockCharPseudoDevFileIO = CMockCharPseudoDevFileIO
295+
296+
# Use the class as a proxy to the io module members.
297+
def __getattr__(self, name):
298+
return getattr(io, name)
299+
300+
301+
class PyTestCase(unittest.TestCase):
302+
io = pyio
303+
is_C = False
304+
305+
MockRawIO = PyMockRawIO
306+
MisbehavedRawIO = PyMisbehavedRawIO
307+
MockFileIO = PyMockFileIO
308+
CloseFailureIO = PyCloseFailureIO
309+
MockNonBlockWriterIO = PyMockNonBlockWriterIO
310+
MockUnseekableIO = PyMockUnseekableIO
311+
MockRawIOWithoutRead = PyMockRawIOWithoutRead
312+
SlowFlushRawIO = PySlowFlushRawIO
313+
MockCharPseudoDevFileIO = PyMockCharPseudoDevFileIO
314+
315+
# Use the class as a proxy to the _pyio module members.
316+
def __getattr__(self, name):
317+
return getattr(pyio, name)

0 commit comments

Comments
 (0)